/*
 *    ### 工具类函数 ###
 * 	  @author ：王劲翔
 * 	  @describe：此JS文件是用来保存工具类函数或者表达式的
 * 	  @import：下载该JS文件，并在HTML中引入该JS文件即可
 */

let inputStr = ``
/**
 * prompt方法，文字输入限制
 */
const userInput = {
	/**
	 * 禁止输入空字符串
	 * @param {输入框提示文字} promptInfo String
	 * @param {空输入提示文字} errInfoNull String
	 * @returns String
	 */
	Null: function (promptInfo = ``, errInfoNull = ``) {
		if (!promptInfo) promptInfo = `请输入：`
		if (!errInfoNull) errInfoNull = `输入为空！`
		for (let i = true; i; ) {
			inputStr = prompt(promptInfo)
			!inputStr ? alert(errInfoNull) : (i = false)
		}
		return inputStr
	},
	/**
	 * 仅可以输入给定的数组内容
	 * @param {存放内容的数组} arr Array
	 * @param {输入框提示文字} promptInfo String
	 * @param {输入字符非数组内容提示文字} errQualifiedInfo String
	 * @param {空输入提示文字} errInfoNull String
	 * @returns String
	 */
	ArrLimit: function (arr = [], promptInfo = ``, errQualifiedInfo = ``, errInfoNull = ``) {
		if (!promptInfo) promptInfo = `请输入：`
		if (!errQualifiedInfo) errQualifiedInfo = `非限定字符！`
		if (!errInfoNull) errInfoNull = `输入为空！`
		for (let i = true; i; ) {
			inputStr = prompt(promptInfo)
			if (!inputStr) {
				alert(errInfoNull)
			} else {
				for (let j = 0; j < arr.length; j++) {
					if (inputStr === arr[j] + ``) {
						i = false
						break
					}
				}
				if (i) alert(errQualifiedInfo)
			}
		}
		return inputStr
	},
	/**
	 * 仅允许输入数字
	 * @param {输入框提示文字} promptInfo String
	 * @param {非数字提示文字} errInfoNaN String
	 * @param {空输入提示文字} errInfoNull String
	 * @returns Number
	 */
	Number: function (promptInfo = ``, errInfoNaN = ``, errInfoNull = ``) {
		if (!promptInfo) promptInfo = `请输入数字：`
		if (!errInfoNaN) errInfoNaN = `非数字！`
		if (!errInfoNull) errInfoNull = `输入为空！`
		for (let i = true; i; ) {
			inputStr = prompt(promptInfo)
			!inputStr ? alert(errInfoNull) : +inputStr || +inputStr + 1 ? (i = false) : alert(errInfoNaN)
		}
		return +inputStr
	},
	/**
	 * 仅允许输入限定范围的数字
	 * @param {数字范围下限} min Number
	 * @param {数字范围上限} max Number
	 * @param {输入框提示文字} promptInfo String
	 * @param {非范围数字提示文字} errScopeInfo String
	 * @param {非数字提示文字} errInfoNaN String
	 * @param {空输入提示文字} errInfoNull String
	 * @returns Number
	 */
	NumberScope: function (min = 0, max = 1, promptInfo = ``, errScopeInfo = ``, errInfoNaN = ``, errInfoNull = ``) {
		if (!promptInfo) promptInfo = `请输入数字：`
		if (!errScopeInfo) errScopeInfo = `超过数字范围！`
		if (!errInfoNaN) errInfoNaN = `非数字！`
		if (!errInfoNull) errInfoNull = `输入为空！`
		for (let i = true; i; ) {
			inputStr = prompt(promptInfo)
			!inputStr ? alert(errInfoNull) : +inputStr || +inputStr + 1 ? (+inputStr > max || +inputStr < min ? alert(errScopeInfo) : (i = false)) : alert(errInfoNaN)
		}
		return +inputStr
	}
}

/**
 * console.log方法，控制台打印输出
 */
const Log = {
	/**
	 * 将数组内容依次打印在控制台
	 * @param {存放打印内容的数组} arr Array
	 */
	Line: function (arr = []) {
		for (let i = 0; i < arr.length; i++) {
			console.log(arr[i])
		}
	},
	/**
	 * 打印指定颜色的内容到控制台
	 * @param {打印内容} info String
	 * @param {颜色} color String
	 */
	Color: function (info = "", color = "") {
		console.log(`%c` + info, `color:${color}`)
	}
}

/**
 * 秒数格式化，根据输入秒数，转化为年月日时分秒格式，如果某一项为零则不打印
 * @param {秒数} second Number
 * @param {年月日分隔符} separatorYMD String
 * @param {日与时的分隔符} separatorDH String
 * @param {时分秒分隔符} separatorHMS String
 * @returns String
 */
function formatSecond(second, separatorYMD = `/`, separatorDH = ` `, separatorHMS = `:`) {
	let formatStr = ""
	let Y = parseInt(second / 60 / 60 / 24 / 365)
	let M = parseInt(second / 60 / 60 / 24 / 30.5) % 12
	let D = parseInt(second / 60 / 60 / 24) % 30.5
	let h = parseInt(second / 60 / 60) % 24
	let m = parseInt(second / 60) % 60
	let s = parseInt(second % 60)
	Y ? (formatStr += Y + "年" + separatorYMD) : ""
	M ? (formatStr += (M < 10 ? `0` + M : M) + "月" + separatorYMD) : ""
	D ? (formatStr += (D < 10 ? `0` + D : D) + "日" + separatorDH) : ""
	h ? (formatStr += (h < 10 ? `0` + h : h) + "时" + separatorHMS) : ""
	m ? (formatStr += (m < 10 ? `0` + m : m) + "分" + separatorHMS) : ""
	formatStr += (s < 10 ? `0` + s : s) + "秒"
	return formatStr
}

let result = 0
let resultArr = [0]
/**
 * 数字处理
 */
const Digit = {
	/**
	 * 精确70位的圆周率
	 */
	PI: 3.1415926535897932384626433832795028841971693993751058209741445923078164,
	/**
	 * 精确70位的自然对数e
	 */
	E: 2.7182818284590452353602874713526624977572470936999595749669676277240766,
	/**
	 * 精确70位的黄金分割数Ф
	 */
	FI: 0.6180339887498948482045868343656381177203091798057628621354486227052604,
	/**
	 * 将数组内容求和
	 * @param {需要求和的数组} numArr NumberArray
	 * @returns Number
	 */
	sum: function (numArr = []) {
		if (!numArr.length) return NaN
		result = 0
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			result += numArr[i]
		}
		return result
	},
	/**
	 * 输出数组中的最小值
	 * @param {需要求最小值的数组} numArr NumberArray
	 * @returns Number
	 */
	min: function (numArr = []) {
		if (!numArr.length) return NaN
		result = numArr[0]
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			if (numArr[i] < result) result = numArr[i]
		}
		return result
	},
	/**
	 * 输出数组中的最大值
	 * @param {需要求最大值的数组} numArr NumberArray
	 * @returns Number
	 */
	max: function (numArr = []) {
		if (!numArr.length) return NaN
		result = numArr[0]
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			if (numArr[i] > result) result = numArr[i]
		}
		return result
	},
	/**
	 * 返回数组中的全部奇数
	 * @param {需要求全部奇数的数组} numArr NumberArray
	 * @returns NumberArray
	 */
	odd: function (numArr = []) {
		if (!numArr.length) return NaN
		resultArr = []
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			if (numArr[i] % 2) resultArr.push(numArr[i])
		}
		return resultArr
	},
	/**
	 * 返回数组中的全部偶数
	 * @param {需要求全部偶数的数组} numArr NumberArray
	 * @returns NumberArray
	 */
	even: function (numArr = []) {
		if (!numArr.length) return NaN
		resultArr = []
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			if (!(numArr[i] % 2)) resultArr.push(numArr[i])
		}
		return resultArr
	},
	/**
	 * 返回数组中全部大于than的数
	 * @param {需求数组} numArr NumberArray
	 * @param {大于某数} than Number
	 * @returns NumberArray
	 */
	greater: function (numArr = [], than = 0) {
		if (!numArr.length) return NaN
		resultArr = []
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			if (!(numArr[i] > than)) resultArr.push(numArr[i])
		}
		return resultArr
	},
	/**
	 * 返回数组中全部小于than的数
	 * @param {需求数组} numArr NumberArray
	 * @param {小于某数} than Number
	 * @returns NumberArray
	 */
	less: function (numArr = [], than = 0) {
		if (!numArr.length) return NaN
		resultArr = []
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			if (!(numArr[i] < than)) resultArr.push(numArr[i])
		}
		return resultArr
	},
	/**
	 * 返回数组中能被divisor整除的所有数
	 * @param {需要求能被某个数整除的数组} numArr NumberArray
	 * @param {其他数能被此数整除} divisor Number
	 * @returns NumberArray
	 */
	aliquot: function (numArr = [], divisor) {
		if (!numArr.length) return NaN
		resultArr = []
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			if (!(numArr[i] % divisor)) resultArr.push(numArr[i])
		}
		return resultArr
	},
	/**
	 * 返回数组中的全部质数
	 * @param {需要求全部质数的数组} numArr NumberArray
	 * @returns NumberArray
	 */
	prime: function (numArr = []) {
		if (!numArr.length) return NaN
		resultArr = []
		let isPrime = true
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			for (let j = 2; j < numArr[i] && isPrime; j++) {
				if (!(numArr[i] % j)) isPrime = false
			}
			if (isPrime) resultArr.push(numArr[i])
			isPrime = true
		}
		return resultArr
	},
	/**
	 * 返回数组中的全部合数
	 * @param {需要求全部合数的数组} numArr NumberArray
	 * @returns NumberArray
	 */
	composite: function (numArr = []) {
		if (!numArr.length) return NaN
		resultArr = []
		let isComposite = false
		for (let i = 0; i < numArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			for (let j = 2; j < numArr[i] && !isComposite; j++) {
				if (!(numArr[i] % j)) isComposite = true
			}
			if (isComposite) resultArr.push(numArr[i])
			isComposite = false
		}
		return resultArr
	},
	/**
	 * 升序排列数组
	 * @param {需要被升序排列的数组} numArr NumberArray
	 * @returns NumberArray
	 */
	ascending: function (numArr = []) {
		if (!numArr.length) return NaN
		resultArr = numArr
		for (let i = 0; i < resultArr.length; i++) {
			// if(!Number(numArr[i]))return NaN
			for (let j = 0; j < resultArr.length - i; j++) {
				if (j + 1 < resultArr.length) {
					if (resultArr[j] > resultArr[j + 1]) {
						let temp = resultArr[j + 1]
						resultArr[j + 1] = resultArr[j]
						resultArr[j] = temp
					}
				}
			}
		}
		return resultArr
	},
	/**
	 * 降序排列数组
	 * @param {需要被降序排列的数组} numArr NumberArray
	 * @returns NumberArray
	 */
	descending: function (numArr = []) {
		if (!numArr.length) return NaN
		resultArr = numArr
		for (let i = 0; i < resultArr.length; i++) {
			if (!Number(numArr[i])) return NaN
			for (let j = 0; j < resultArr.length - i; j++) {
				if (j + 1 < resultArr.length) {
					if (resultArr[j] < resultArr[j + 1]) {
						let temp = resultArr[j + 1]
						resultArr[j + 1] = resultArr[j]
						resultArr[j] = temp
					}
				}
			}
		}
		return resultArr
	},
	/**
	 * 保留指定小数位数(直接保留)
	 * @param {需要保留小数位数的数字} num Float
	 * @param {保留位数} place Number
	 * @returns Float
	 */
	Place: function (num = 0.0, place = 2) {
		let temp = Math.pow(10, place)
		return parseInt(num * temp) / temp
	},
	/**
	 * 保留指定小数位数(四舍五入)
	 * @param {需要保留小数位数的数字} num Float
	 * @param {四舍五入保留位数} place Number
	 * @returns Float
	 */
	PlaceRounded: function (num = 0.0, place = 2) {
		return +parseFloat(num + 0).toFixed(place)
	},
	/**
	 * 整数随机数
	 * @param {随机整数的最小值} min Number
	 * @param {随机整数的最大值} max Number
	 * @param {是否需要包含最大值} closed Boolean
	 * @returns Number
	 */
	randomInt: function (min = 0, max = 10, closed = false) {
		return closed ? parseInt(Math.random() * (max - min + 1) + min) : parseInt(Math.random() * (max - min) + min)
	},
	/**
	 * 小数随机数
	 * @param {随机数的最小值} min Number
	 * @param {随机数的最大值} max Number
	 * @param {是否需要包含最大值} closed Boolean
	 * @returns Float
	 */
	randomFloat: function (min = 0, max = 10, closed = false) {
		return closed ? Math.random() * (max - min + 1) + min : Math.random() * (max - min) + min
	}
}

let resultStrArr = []
/**
 * 字符串处理类
 */
const Str = {
	/**
	 * 按照顺序分离字符串中的数字、字母与其他字符
	 * @param {需要处理的字符串} str String
	 * @returns Array
	 */
	subArr: function (str = "") {
		let strTemp = "",
			numTemp = "",
			otherTemp = ""
		for (let i = 0; i < str.length; i++) {
			let temp = str.substring(i, i + 1)
			if (temp != " ") {
				if (temp != 0) {
					if (Number(temp)) {
						numTemp += temp
						strTemp ? resultStrArr.push(strTemp) : "", otherTemp ? resultStrArr.push(otherTemp) : ""
						;(strTemp = ""), (otherTemp = "")
					} else if (/^[A-Za-z]+$/.test(temp)) {
						strTemp += temp
						numTemp ? resultStrArr.push(+numTemp) : "", otherTemp ? resultStrArr.push(otherTemp) : ""
						;(numTemp = ""), (otherTemp = "")
					} else {
						otherTemp += temp
						numTemp ? resultStrArr.push(+numTemp) : "", strTemp ? resultStrArr.push(strTemp) : ""
						;(numTemp = ""), (strTemp = "")
					}
				} else {
					numTemp += temp
					strTemp ? resultStrArr.push(strTemp) : "", otherTemp ? resultStrArr.push(otherTemp) : ""
					;(strTemp = ""), (otherTemp = "")
				}
			}
		}
		strTemp ? resultStrArr.push(strTemp) : ""
		numTemp ? resultStrArr.push(+numTemp) : ""
		otherTemp ? resultStrArr.push(otherTemp) : ""
		return resultStrArr
	},

	/**
	 * 去除字符串首尾空格
	 * @param {需要处理的字符串} str String
	 * @returns String
	 */
	removeSpace: function (str = "") {
		if (str.substring(0, 1) == " ") {
			str = str.substring(1, str.length)
		}
		if (str.substring(str.length - 1, str.length) == " ") {
			str = str.substring(0, str.length - 1)
		}
		return str
	},

	/**
	 * 去除字符串中的全部空格
	 * @param {需要处理的字符串} str String
	 * @returns String
	 */
	removeAllSpace: function (str = "") {
		return str
			.split("")
			.map(item => {
				if (item != " ") return item
			})
			.join("")
	},

	/**
	 * 将字符串中的字符每num个为一组，储存为数组，不足字数的直接储存
	 * @param {需要处理的字符串} str String
	 * @param {分段字数} num Number
	 * @returns Array
	 */
	section: function (str = "", num = 1) {
		if (str.length <= num || !num || typeof num !== "number") return Array(str)
		let tempArr = []
		while (true) {
			tempArr.push(str.substring(0, num))
			str = str.substring(num, str.length)
			if (str.length <= num) {
				tempArr.push(str)
				break
			}
		}
		return tempArr
	},

	/**
	 * 将字符串按照指定字符分割成数组
	 * @param {需要处理的字符串} str
	 * @param {分割字符} char
	 * @returns Array
	 */
	subChar: function (str = "", char = "") {
		if (typeof str !== "string" || str.indexOf(char) == -1) return Array(str)
		str = str.split("")
		let temp = ""
		let tempArr = []
		for (let i = 0; i < str.length; i++) {
			if (str[i] != char) {
				temp += str[i]
			} else {
				if (temp) tempArr.push(temp)
				temp = ""
			}
		}
		if (temp) tempArr.push(temp)
		return tempArr
	}
}

/**
 *  颜色转换类
 */
const Color = {
	/**
	 * 将RGB转换为16进制 不加#号
	 * @param {红色数值或者rgb格式字符串} R_rgb Number||String
	 * @param {绿色数值} G Number
	 * @param {蓝色数值} B Number
	 * @returns String
	 */
	toHex: function (R_rgb = 0, G = 0, B = 0) {
		if ((R_rgb + "").substring(0, 4).toLowerCase() == "rgb(" || (R_rgb + "").substring(0, 1).toLowerCase() == "(") {
			let rgbArr = R_rgb.split(",")
			R_rgb = parseInt(rgbArr[0].split("(")[1])
			G = parseInt(rgbArr[1])
			B = parseInt(rgbArr[2].split(")")[0])
		}
		if (R_rgb > 255 || R_rgb < 0 || G > 255 || G < 0 || B > 255 || B < 0 || R_rgb == undefined || G == undefined || B == undefined) return undefined
		let hex = ``
		getHex(R_rgb)
		getHex(G)
		getHex(B)
		return hex
		function getHex(C) {
			switchHex(parseInt(C / 16))
			switchHex(C % 16)
			function switchHex(num) {
				switch (num) {
					case 10:
						hex += "A"
						break
					case 11:
						hex += "B"
						break
					case 12:
						hex += "C"
						break
					case 13:
						hex += "D"
						break
					case 14:
						hex += "E"
						break
					case 15:
						hex += "F"
						break
					default:
						hex += num
				}
			}
		}
	},
	toRGB: function (Hex) {}
}

/**
 * 计时器相关方法
 */
const Timer = {
	/**
	 * 将给定元素的内容变成倒计时
	 * @param {需要用来显示的元素} element String
	 * @param {倒计时的开始时间} start Number
	 * @param {倒计时的结束时间_一般不修改} end Number
	 */
	countdown: function (element, start = 10, end = 0) {
		let time = setInterval(function () {
			start < end ? (element.innerHTML = start--) : clearInterval(time)
		}, 1000)
	},
	/**
	 * 将给定元素的内容变成正向计时
	 * @param {需要用来显示的元素} element String
	 * @param {计时的结束时间} end Number
	 * @param {计时的开始时间_一般不修改} start Number
	 */
	timing: function (element, end = 10, start = 0) {
		let time = setInterval(function () {
			start <= end ? (element.innerHTML = start++) : clearInterval(time)
		}, 1000)
	},
	/**
	 * 将数组的内容依次刷新显示
	 * @param {需要用来显示的元素} element String
	 * @param {顺序依次显示的数组} arr Array
	 * @param {间隔时间} interval Number
	 * @param {是否一直从头循环} cycle Boolean
	 */
	shuffling: function (element, arr = [], interval = 1000, cycle = false) {
		let index = 0
		let time = setInterval(function () {
			index < arr.length ? (element.innerHTML = arr[index++]) : cycle ? (index = 0) : clearInterval(time)
		}, interval)
	},
	/**
	 * 循环轮播图
	 * @param {需要用来更换图片的img标签元素_CSS选择器} imgElement String
	 * @param {顺序依次显示的图片路径数组} arrURL Array
	 * @param {间隔时间} interval Number
	 */
	shufflingIMG: function (imgElement, arrURL = [], interval = 1000) {
		let index = 0
		imgElement = document.querySelector(imgElement)
		let time = setInterval(function () {
			imgElement.src = arrURL[index]
			++index == arrURL.length ? (index = 0) : ``
		}, interval)
	},
	/**
	 * 循环轮播图、进度点
	 * @param {需要用来更换图片的img标签元素_CSS选择器} imgElement String
	 * @param {需要用来显示轮换进度的同名兄弟标签元素_CSS选择器} pointElement String
	 * @param {需要用来轮换的同名兄弟标签元素的样式类名_不写符号只写名字} pointActiveClassName String
	 * @param {顺序依次显示的图片路径数组} arrURL Array
	 * @param {间隔时间} interval Number
	 */
	shufflingIMG_point: function (imgElement, pointElement, pointActiveClassName, arrURL = [], interval = 1000) {
		let index = 0
		imgElement = document.querySelector(img)
		let time = setInterval(function () {
			imgElement.src = arrURL[index]
			document.querySelector("." + pointActiveClassName).classList.remove(pointActiveClassName)
			document.querySelector(pointElement + `:nth-child(${index + 1})`).classList.toggle(pointActiveClassName)
			++index == arrURL.length ? (index = 0) : ``
		}, interval)
	},
	/**
	 * 循环轮播图、进度点、上下按钮
	 * @param {轮播图全组件的父元素_CSS选择器} superiorElement String
	 * @param {需要用来更换图片的img标签元素_CSS选择器} imgElement String
	 * @param {需要用来显示轮换进度的同名兄弟标签元素_CSS选择器} pointElement String
	 * @param {需要用来轮换的同名兄弟标签元素的样式类名_不写符号只写名字} pointActiveClassName String
	 * @param {显示上一张的按钮或点击元素_CSS选择器} prevBtn String
	 * @param {显示下一张的按钮或点击元素_CSS选择器} nextBtn String
	 * @param {顺序依次显示的图片路径数组} arrURL Array
	 * @param {间隔时间} time Number
	 */
	shufflingIMG_point_btn: function (superiorElement, imgElement, pointElement, pointActiveClassName, prevBtn, nextBtn, arrURL = [], time = 1000) {
		superiorElement = document.querySelector(superiorElement)
		imgElement = document.querySelector(imgElement)
		let index = 0
		let SetInterval = 0
		Interval()
		function Interval() {
			SetInterval = setInterval(function () {
				++index == arrURL.length ? (index = 0) : ``
				play()
			}, time)
		}
		superiorElement.addEventListener("mouseenter", function () {
			clearInterval(SetInterval)
		})
		superiorElement.addEventListener("mouseleave", function () {
			Interval()
		})
		document.querySelector(prevBtn).addEventListener("click", function () {
			--index < 0 ? (index = arrURL.length - 1) : ``
			play()
		})
		document.querySelector(nextBtn).addEventListener("click", function () {
			++index >= arrURL.length ? (index = 0) : ``
			play()
		})

		function play() {
			imgElement.src = arrURL[index]
			document.querySelector(`.` + pointActiveClassName).classList.remove(pointActiveClassName)
			document.querySelector(pointElement + `:nth-child(${index + 1})`).classList.add(pointActiveClassName)
		}
	},
	/**
	 * 循环轮播图、进度点、上下按钮、轮播标题
	 * @param {轮播图全组件的父元素_CSS选择器} superiorElement String
	 * @param {需要用来更换图片的img标签元素_CSS选择器} imgElement String
	 * @param {图片地址在对象中的属性名} objImgKey String
	 * @param {轮换进度的同名兄弟标签元素_CSS选择器} pointElement String
	 * @param {轮换的同名兄弟类名_不写符号只写名字} pointActiveClassName String
	 * @param {标题文字轮换显示的类名_CSS选择器} textElement String
	 * @param {标题文字在对象中的属性名} objTextKey String
	 * @param {上一张的点击元素_CSS选择器} prevBtn String
	 * @param {下一张的点击元素_CSS选择器} nextBtn String
	 * @param {图片路径与标题文字的对象数组} arrObj Array
	 * @param {间隔时间} time Number
	 */
	shufflingAll: function (
		superiorElement = "",
		imgElement = "",
		objImgKey = "",
		pointElement = "",
		pointActiveClassName = "",
		textElement = "",
		objTextKey = "",
		prevBtn = "",
		nextBtn = "",
		arrObj = [],
		time = 1000
	) {
		superiorElement = document.querySelector(superiorElement)
		imgElement = document.querySelector(imgElement)
		textElement = document.querySelector(textElement)
		let index = 0
		let SetInterval = 0
		Interval()
		function Interval() {
			SetInterval = setInterval(function () {
				++index == arrObj.length ? (index = 0) : ``
				play()
			}, time)
		}
		superiorElement.addEventListener("mouseenter", function () {
			clearInterval(SetInterval)
		})
		superiorElement.addEventListener("mouseleave", function () {
			Interval()
		})
		document.querySelector(prevBtn).addEventListener("click", function () {
			--index < 0 ? (index = arrObj.length - 1) : ``
			play()
		})
		document.querySelector(nextBtn).addEventListener("click", function () {
			++index >= arrObj.length ? (index = 0) : ``
			play()
		})

		function play() {
			imgElement.src = arrObj[index][objImgKey]
			textElement.innerHTML = arrObj[index][objTextKey]
			document.querySelector(`.` + pointActiveClassName).classList.remove(pointActiveClassName)
			document.querySelector(pointElement + `:nth-child(${index + 1})`).classList.add(pointActiveClassName)
		}
	}
}

/**
 * 时间类
 */
const FormatDate = {
	/**
	 * 获取自定义分隔符的时分秒
	 * @param {时分秒的分隔符} Separator_HMS string
	 * @returns string
	 */
	getFormatDate_HMS: function (Separator_HMS = ":") {
		const date = new Date()
		const Hours = format(date.getHours().toString())
		const Minutes = format(date.getMinutes().toString())
		const Seconds = format(date.getSeconds().toString())
		function format(str) {
			return str.length < 2 ? "0" + str : str
		}
		return Hours + Separator_HMS + Minutes + Separator_HMS + Seconds
	},

	/**
	 * 获取自定义分隔符的年月日
	 * @param {年月日的分隔符} Separator_YMD string
	 * @returns string
	 */
	getFormatDate_YMD: function (Separator_YMD = "/") {
		const date = new Date()
		const Year = date.getFullYear()
		const Month = format(date.getMonth().toString())
		const Day = format(date.getDay().toString())
		function format(str) {
			return str.length < 2 ? "0" + str : str
		}
		return Year + Separator_YMD + Month + Separator_YMD + Day
	},

	/**
	 * 获取自定义分隔符的年月日时分秒
	 * @param {年月日的分隔符} Separator_YMD string
	 * @param {日与时之间的分隔符} Separator_DH string
	 * @param {时分秒的分隔符} Separator_HMS string
	 * @returns string
	 */
	getFormatDate: function (Separator_YMD = "/", Separator_DH = " ", Separator_HMS = ":") {
		const date = new Date()
		const Year = date.getFullYear()
		const Month = format(date.getMonth().toString())
		const Day = format(date.getDay().toString())
		const Hours = format(date.getHours().toString())
		const Minutes = format(date.getMinutes().toString())
		const Seconds = format(date.getSeconds().toString())
		function format(str) {
			return str.length < 2 ? "0" + str : str
		}
		return Year + Separator_YMD + Month + Separator_YMD + Day + Separator_DH + Hours + Separator_HMS + Minutes + Separator_HMS + Seconds
	}
}

/**
 *	axios 快捷类
 */
const ax = {
	/**
	 * 接口地址
	 */
	url: "",
	/**
	 * axios查询参数
	 */
	params: {},
	/**
	 * axios请求体
	 */
	data: {},
	/**
	 * axios 请求头
	 */
	headers: {},
	/**
	 * 基地址
	 */
	baseURL: "",
	/**
	 * 公共配置
	 */
	config: {},
	/**
	 * 公共配置数据，禁止修改
	 */
	_configData: {},
	/**
	 * 配置函数
	 */
	_Interceptor: function () {
		for (const key in this.config) {
			if (typeof this.config[key] == "function") {
				this._configData[key] = this.config[key]()
			}
		}
		for (const key in this._configData) {
			if (key == "url") {
				this.url = this._configData.url
			}
			if (this._configData.params) {
				for (const key in this._configData.params) {
					this.params[key] = this._configData.params[key]
				}
			}
			if (this._configData.data) {
				for (const key in this._configData.data) {
					this.data[key] = this._configData.data[key]
				}
			}
			if (this._configData.headers) {
				for (const key in this._configData.headers) {
					this.headers[key] = this._configData.headers[key]
				}
			}
		}
	},
	/**
	 * axios POST请求
	 * @param {请求接口} url String
	 * @param {请求参数} params Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 */
	POSTQuery: function (url = "", params = {}, resultFunction = result => {}, errorFunction = err => {}) {
		if (!arguments.length) {
			url = this.url
			params = this.params
		} else if (url instanceof Function) {
			errorFunction = params
			resultFunction = url
			params = this.params
			url = this.url
		} else if (url instanceof Object) {
			errorFunction = resultFunction
			resultFunction = params
			params = url
			url = this.url
		}
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method: "POST",
			headers: this.headers,
			params: params
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios POST请求
	 * @param {请求接口} url String
	 * @param {数据传输} data Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 */
	POSTBody: function (url = "", data = {}, resultFunction = result => {}, errorFunction = err => {}) {
		if (!arguments.length) {
			url = this.url
			data = this.data
		} else if (url instanceof Function) {
			errorFunction = data
			resultFunction = url
			data = this.data
			url = this.url
		} else if (url instanceof Object) {
			errorFunction = resultFunction
			resultFunction = data
			data = url
			url = this.url
		}
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method: "POST",
			headers: this.headers,
			data: data
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios GET请求
	 * @param {请求接口} url String
	 * @param {请求参数} params Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 */
	GETQuery: function (url = "", params = {}, resultFunction = result => {}, errorFunction = err => {}) {
		if (!arguments.length) {
			url = this.url
			params = this.params
		} else if (url instanceof Function) {
			errorFunction = params
			resultFunction = url
			params = this.params
			url = this.url
		} else if (url instanceof Object) {
			errorFunction = resultFunction
			resultFunction = params
			params = url
			url = this.url
		}
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method: "GET",
			headers: this.headers,
			params: params
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios GET请求
	 * @param {请求接口} url String
	 * @param {数据传输} data Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 *
	 */
	GETBody: function (url = "", data = {}, resultFunction = result => {}, errorFunction = err => {}) {
		if (!arguments.length) {
			url = this.url
			data = this.data
		} else if (url instanceof Function) {
			errorFunction = data
			resultFunction = url
			data = this.data
			url = this.url
		} else if (url instanceof Object) {
			errorFunction = resultFunction
			resultFunction = data
			data = url
			url = this.url
		}
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method: "GET",
			headers: this.headers,
			data: data
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios PUT请求
	 * @param {请求接口} url String
	 * @param {数据传输} data Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 *
	 */
	PUT: function (url = "", data = {}, resultFunction = result => {}, errorFunction = err => {}) {
		if (!arguments.length) {
			url = this.url
			data = this.data
		} else if (url instanceof Function) {
			errorFunction = data
			resultFunction = url
			data = this.data
			url = this.url
		} else if (url instanceof Object) {
			errorFunction = resultFunction
			resultFunction = data
			data = url
			url = this.url
		}
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method: "PUT",
			headers: this.headers,
			data: data
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios DELETE请求
	 * @param {请求接口} url String
	 * @param {数据传输} data Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 *
	 */
	DELETE: function (url = "", data = {}, resultFunction = result => {}, errorFunction = err => {}) {
		if (!arguments.length) {
			url = this.url
			data = this.data
		} else if (url instanceof Function) {
			errorFunction = data
			resultFunction = url
			data = this.data
			url = this.url
		} else if (url instanceof Object) {
			errorFunction = resultFunction
			resultFunction = data
			data = url
			url = this.url
		}
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method: "DELETE",
			headers: this.headers,
			data: data
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios PATCH请求
	 * @param {请求接口} url String
	 * @param {数据传输} data Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 *
	 */
	PATCH: function (url = "", data = {}, resultFunction = result => {}, errorFunction = err => {}) {
		if (!arguments.length) {
			url = this.url
			data = this.data
		} else if (url instanceof Function) {
			errorFunction = data
			resultFunction = url
			data = this.data
			url = this.url
		} else if (url instanceof Object) {
			errorFunction = resultFunction
			resultFunction = data
			data = url
			url = this.url
		}
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method: "PATCH",
			headers: this.headers,
			data: data
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios 自定义请求
	 * @param {请求接口} url String
	 * @param {请求方式} method String
	 * @param {请求参数} params Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result Object
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 *
	 */
	customQuery: function (url = "", method = "", params = {}, resultFunction = result => {}, errorFunction = err => {}) {
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method,
			headers: this.headers,
			params: params
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios 自定义数据交互
	 * @param {请求接口} url String
	 * @param {请求方式} method String
	 * @param {数据传输} data Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result Object
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 * @returns Promise
	 *
	 */
	customBody: function (url = "", method = "", data = {}, resultFunction = result => {}, errorFunction = err => {}) {
		this._Interceptor()
		url = this.baseURL + url
		const axp = axios({
			url,
			method,
			headers: this.headers,
			data: data
		})
		axp
			.then(result => {
				resultFunction(result)
			})
			.catch(err => {
				errorFunction(err)
			})
		return axp
	},

	/**
	 * axios 文件传输
	 * @param {file属性的input} uploadEle Element
	 * @param {文件传输属性名_可传数组} fileKey String Array
	 * @param {请求接口} url String
	 * @param {请求方式} method String
	 * @param {数据传输} data Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 */
	fileBody: function (uploadEle, fileKey = [], url = "", method = "", data = {}, resultFunction = result => {}, errorFunction = err => {}) {
		const files = e.target.files
		if (typeof fileKey === "string") {
			if (uploadEle.multiple) {
				if (files.length == 1) {
					data.append(fileKey, files[0])
				} else {
					for (let i = 0; i < files.length; i++) {
						data.append(fileKey + "" + i, files[i])
					}
				}
			} else {
				data.append(fileKey, files[0])
			}
		} else {
			for (let i = 0; i < files.length; i++) {
				data.append(fileKey[i], files[i])
			}
		}
		this._Interceptor()
		url = this.baseURL + url
		uploadEle.addEventListener("change", function (e) {
			axios({
				url,
				method,
				headers: this.headers,
				data
			})
				.then(result => {
					resultFunction(result)
				})
				.catch(err => {
					errorFunction(err)
				})
		})
	},

	/**
	 * axios 文件传输，使用FormData格式
	 * @param {file属性的input} uploadEle Element
	 * @param {文件传输属性名_可传数组} fileKey String Array
	 * @param {请求接口} url String
	 * @param {请求方式} method String
	 * @param {数据传输} data Object
	 * @param {返回结果处理函数} resultFunction Function
	 * @param {处理函数形参} resultFunction_result
	 * @param {异常处理函数} errorFunction Function
	 * @param {异常处理函数形参} errorFunction_err
	 */
	fileBodyFormData: function (uploadEle, fileKey = [], url = "", method = "", data = {}, resultFunction = result => {}, errorFunction = err => {}) {
		uploadEle.addEventListener("change", function (e) {
			const files = e.target.files
			const formData = new FormData()
			if (typeof fileKey === "string") {
				if (uploadEle.multiple) {
					if (files.length == 1) {
						formData.append(fileKey, files[0])
					} else {
						for (let i = 0; i < files.length; i++) {
							formData.append(fileKey + "" + i, files[i])
						}
					}
				} else {
					formData.append(fileKey, files[0])
				}
			} else {
				for (let i = 0; i < files.length; i++) {
					formData.append(fileKey[i], files[i])
				}
			}
			for (const key in data) {
				formData.append(key, data[key])
			}
			this._Interceptor()
			url = this.baseURL + url
			axios({
				url,
				method,
				headers: this.headers,
				data: formData
			})
				.then(result => {
					resultFunction(result)
				})
				.catch(err => {
					errorFunction(err)
				})
		})
	}
}

let toastBox = ""
let isToast = false
/**
 * 浮窗类
 */
const Modal = {
	/**
	 * 选择型浮窗，具有确定与取消按钮，出现时背景黑幕
	 * @param {显示标题} title String
	 * @param {显示内容} content String
	 * @param {确认按钮执行函数} sureFunction Function
	 */
	question: function (title = "", content = "", sureFunction = () => {}) {
		const box = document.createElement("div")
		box.classList.add("questionModal")
		box.innerHTML = `
		<div id="questionModal_modalMask"></div>
		<div id="questionModal_content">
			<h4 id="questionModal_H">${title}</h4>
			<p id="questionModal_p">${content}</p>
			<div id="questionModal_Btns">
				<a id="questionModal_cancel" href="javascript:;">取消</a>
				<a id="questionModal_sure" href="javascript:;">确认</a>
			</div>
		</div>
		`
		document.body.append(box)
		boxStyle()
		setTimeout(() => {
			box.style.opacity = 1
		}, 50)
		//确认按钮
		questionModal_sure.addEventListener("click", () => {
			remove()
			sureFunction()
		})
		//取消按钮
		questionModal_cancel.addEventListener("click", () => {
			remove()
		})
		//移除盒子
		function remove() {
			box.style.opacity = 0
			setTimeout(() => {
				box.remove()
			}, 300)
		}
		//style样式
		function boxStyle() {
			box.style.display = "none"
			box.style.opacity = 0
			box.style.height = "100vh"
			box.style.width = "100vw"
			box.style.position = "absolute"
			box.style.top = "0"
			box.style.left = "0"
			box.style.transition = "all 0.2s"
			box.style.zIndex = "999"
			questionModal_modalMask.style.height = "100%"
			questionModal_modalMask.style.width = "100%"
			questionModal_modalMask.style.backgroundColor = "rgba(0, 0, 0, 0.5)"
			questionModal_modalMask.style.transition = "all 0.3s"
			questionModal_modalMask.style.zIndex = "998"
			questionModal_content.style.width = "450px"
			questionModal_content.style.height = "200px"
			questionModal_content.style.position = "absolute"
			questionModal_content.style.top = "20%"
			questionModal_content.style.left = "50%"
			questionModal_content.style.transform = "translate(-50%, -50%)"
			questionModal_content.style.borderRadius = "15px"
			questionModal_content.style.transition = "all 0.3s"
			questionModal_content.style.boxSizing = "border-box"
			questionModal_content.style.backgroundColor = "#484848"
			questionModal_content.style.display = "flex"
			questionModal_content.style.flexDirection = "column"
			questionModal_content.style.justifyContent = "space-between"
			questionModal_content.style.border = "1px solid #fff"
			questionModal_H.style.padding = "10px"
			questionModal_H.style.paddingBottom = "40px"
			questionModal_H.style.height = "35px"
			questionModal_H.style.lineHeight = "30px"
			questionModal_H.style.fontSize = "20px"
			questionModal_H.style.color = "#fff"
			questionModal_H.style.fontWeight = "normal"
			questionModal_H.style.borderBottom = "1px solid"
			questionModal_H.style.paddingLeft = "10px"
			questionModal_p.style.flex = "1"
			questionModal_p.style.color = "#fff"
			questionModal_p.style.fontSize = "17px"
			questionModal_p.style.paddingLeft = "10px"
			questionModal_p.style.padding = "10px"
			questionModal_Btns.style.display = "flex"
			questionModal_Btns.style.justifyContent = "right"
			questionModal_Btns.style.padding = "10px"
			questionModal_sure.style.textAlign = "center"
			questionModal_sure.style.textDecoration = "none"
			questionModal_sure.style.color = "#fff"
			questionModal_sure.style.display = "block"
			questionModal_sure.style.height = "32px"
			questionModal_sure.style.lineHeight = "32px"
			questionModal_sure.style.borderRadius = "8px"
			questionModal_sure.style.marginRight = "10px"
			questionModal_sure.style.width = "120px"
			questionModal_sure.style.backgroundColor = "rgb(39, 114, 255)"
			questionModal_cancel.style.textAlign = "center"
			questionModal_cancel.style.textDecoration = "none"
			questionModal_cancel.style.color = "#fff"
			questionModal_cancel.style.display = "block"
			questionModal_cancel.style.height = "32px"
			questionModal_cancel.style.lineHeight = "32px"
			questionModal_cancel.style.borderRadius = "8px"
			questionModal_cancel.style.marginRight = "10px"
			questionModal_cancel.style.width = "80px"
			questionModal_cancel.style.backgroundColor = "rgb(119, 119, 119)"
			box.style.display = "block"
		}
	},

	/**
	 * 提示型浮窗，具有确定按钮，出现时背景黑幕
	 * @param {显示标题} title String
	 * @param {显示内容} content String
	 * @param {确认按钮执行函数} sureFunction Function
	 */
	prompt: function (title = "", content = "", sureFunction = () => {}) {
		const box = document.createElement("div")
		box.classList.add("promptModal")
		box.innerHTML = `
		<div id="promptModal_modalMask"></div>
		<div id="promptModal_content">
			<h4 id="promptModal_H">${title}</h4>
			<p id="promptModal_p">${content}</p>
			<div id="promptModal_Btns">
				<a id="promptModal_sure" href="javascript:;">确认</a>
			</div>
		</div>
		`
		document.body.append(box)
		boxStyle()
		setTimeout(() => {
			box.style.opacity = 1
		}, 50)
		//确认按钮
		promptModal_sure.addEventListener("click", () => {
			remove()
			sureFunction()
		})
		//移除盒子
		function remove() {
			box.style.opacity = 0
			setTimeout(() => {
				box.remove()
			}, 300)
		}
		//style样式
		function boxStyle() {
			box.style.display = "none"
			box.style.opacity = 0
			box.style.height = "100vh"
			box.style.width = "100vw"
			box.style.position = "absolute"
			box.style.top = "0"
			box.style.left = "0"
			box.style.transition = "all 0.2s"
			box.style.zIndex = "999"
			promptModal_modalMask.style.height = "100%"
			promptModal_modalMask.style.width = "100%"
			promptModal_modalMask.style.backgroundColor = "rgba(0, 0, 0, 0.5)"
			promptModal_modalMask.style.transition = "all 0.3s"
			promptModal_modalMask.style.zIndex = "998"
			promptModal_content.style.width = "450px"
			promptModal_content.style.height = "200px"
			promptModal_content.style.position = "absolute"
			promptModal_content.style.top = "20%"
			promptModal_content.style.left = "50%"
			promptModal_content.style.transform = "translate(-50%, -50%)"
			promptModal_content.style.borderRadius = "15px"
			promptModal_content.style.transition = "all 0.3s"
			promptModal_content.style.boxSizing = "border-box"
			promptModal_content.style.backgroundColor = "#484848"
			promptModal_content.style.display = "flex"
			promptModal_content.style.flexDirection = "column"
			promptModal_content.style.justifyContent = "space-between"
			promptModal_content.style.border = "1px solid #fff"
			promptModal_H.style.padding = "10px"
			promptModal_H.style.paddingBottom = "40px"
			promptModal_H.style.height = "35px"
			promptModal_H.style.lineHeight = "30px"
			promptModal_H.style.fontSize = "20px"
			promptModal_H.style.color = "#fff"
			promptModal_H.style.fontWeight = "normal"
			promptModal_H.style.borderBottom = "1px solid"
			promptModal_H.style.paddingLeft = "10px"
			promptModal_p.style.flex = "1"
			promptModal_p.style.color = "#fff"
			promptModal_p.style.fontSize = "17px"
			promptModal_p.style.paddingLeft = "10px"
			promptModal_p.style.padding = "10px"
			promptModal_Btns.style.display = "flex"
			promptModal_Btns.style.justifyContent = "right"
			promptModal_Btns.style.padding = "10px"
			promptModal_sure.style.textAlign = "center"
			promptModal_sure.style.textDecoration = "none"
			promptModal_sure.style.color = "#fff"
			promptModal_sure.style.display = "block"
			promptModal_sure.style.height = "32px"
			promptModal_sure.style.lineHeight = "32px"
			promptModal_sure.style.borderRadius = "8px"
			promptModal_sure.style.marginRight = "10px"
			promptModal_sure.style.width = "120px"
			promptModal_sure.style.backgroundColor = "rgb(39, 114, 255)"
			box.style.display = "block"
		}
	},

	/**
	 * 轻提示浮窗。
	 * 可选位置：top、center、bottom
	 * @param {显示内容} content String
	 * @param {显示位置} position String
	 * @param {背景颜色} backgroundColor String
	 * @param {文字颜色} textColor String
	 */
	toast: function (content = "", position = "top", backgroundColor = "rgba(0,0,0,0.7)", textColor = "#fff") {
		if (isToast) toastBox && toastBox.remove()
		isToast = true
		!position && (position = "top")
		!backgroundColor && (backgroundColor = "rgba(0,0,0,0.7)")
		!textColor && (textColor = "#fff")
		const box = document.createElement("div")
		toastBox = box
		box.classList.add("ToastModal")
		box.innerHTML = `
			<p id="ToastModal_p" style="font-size:13px;color:${textColor};">${content}</p>
		`
		document.body.append(box)
		boxStyle()
		setTimeout(() => {
			box.style.opacity = 1
			remove()
		}, 50)
		//移除盒子
		function remove() {
			setTimeout(() => {
				box.style.opacity = 0
				setTimeout(() => {
					box.remove()
					isToast = false
				}, 400)
			}, 3000)
		}
		//style样式
		function boxStyle() {
			box.style.display = "none"
			box.style.opacity = 0
			box.style.width = "280px"
			box.style.height = "40px"
			box.style.backgroundColor = backgroundColor
			box.style.borderRadius = "5px"
			box.style.overflow = "hidden"
			box.style.justifyContent = "center"
			box.style.alignItems = "center"
			box.style.textAlign = "center"
			box.style.position = "absolute"
			if (position == "top") {
				box.style.top = "5%"
				box.style.transform = "translateX(-50%)"
			} else if (position == "center") {
				box.style.top = "50%"
				box.style.transform = "translate(-50%,-50%)"
			} else if (position == "bottom") {
				box.style.bottom = "5%"
				box.style.transform = "translateX(-50%)"
			} else {
				box.style.top = "5%"
				box.style.transform = "translateX(-50%)"
			}
			box.style.left = "50%"
			box.style.transition = "all 0.5s"
			box.style.zIndex = "999"
			box.style.display = "flex"
		}
	},

	/**
	 * 自定义浮窗，需要具有关闭元素，出现时背景黑幕
	 * @param {需要显示的父元素} element
	 * @param {点击让父元素关闭的元素} moveElement
	 */
	custom: function (element, moveElement) {
		const ele = existElement(element, "未找到元素(Modal.custom)")
		const moveEle = existElement(element, "未找到元素(Modal.custom)")
		if (ele[0] && moveEle[0]) {
			const Mask = document.createElement("div")
			Mask.id = "divModal_modalMask"
			document.body.prepend(Mask)
			divModal_modalMask.style.opacity = 0
			divModal_modalMask.style.position = "fixed"
			divModal_modalMask.style.top = "0"
			divModal_modalMask.style.left = "0"
			divModal_modalMask.style.height = "500%"
			divModal_modalMask.style.width = "100%"
			divModal_modalMask.style.backgroundColor = "rgba(0, 0, 0, 0.7)"
			divModal_modalMask.style.transition = "all 0.3s"
			divModal_modalMask.style.zIndex = "998"
			ele[1].style.display = "block"
			ele[1].style.opacity = 0
			ele[1].style.position = "fixed"
			ele[1].style.top = "50%"
			ele[1].style.left = "50%"
			ele[1].style.transform = "translate(-50%, -50%)"
			ele[1].style.transition = "all 0.3s"
			ele[1].style.zIndex = "999"
			setTimeout(() => {
				divModal_modalMask.style.opacity = 1
				ele[1].style.opacity = 1
			}, 50)
			moveEle[1].addEventListener("click", function () {
				ele[1].style.opacity = 0
				divModal_modalMask.style.opacity = 0
				setTimeout(() => {
					ele[1].style.display = "none"
					divModal_modalMask.style.display = "none"
					divModal_modalMask.remove()
				}, 350)
			})
			Mask.addEventListener("click", function () {
				ele[1].style.opacity = 0
				divModal_modalMask.style.opacity = 0
				setTimeout(() => {
					ele[1].style.display = "none"
					divModal_modalMask.style.display = "none"
					divModal_modalMask.remove()
				}, 350)
			})
		}
	}
}

let styleBorder = {}
let styleBackground = {}
let styleOutline = {}
/**
 * form表单类
 */
const form = {
	/**
	 * 根据对象创建表单，并处理执行回调函数
	 * 目前 input 不支持单选、多选和文件
	 * @param {表单标题} title String
	 * @param {组件对象} component Object
	 * @param {提交按钮执行函数} submitFunction Function
	 * @param {表单全部值的对象} submitFunction_value Object
	 *
	 */
	/* component 格式：
	{
		input:{
			type : "text",
			prompt:"说明文字",
			placeholder:"提示文字",
			name:"",
			id:"",
			class:"",
			checked:false,
			multiple:false
		},
		select:{
			prompt:"说明文字",
			name:"",
			id:"",
			class:"",
			option:{
				value:"",
				prompt:"选项文字",
				class:""
			},
		},
		textarea:{
			prompt:"说明文字",
			name:"",
			id:"",
			class:"",
			cols:"30",
			rows:"10"
			resize:"none"
		}
	}
	*/
	Modal: function (title = "", component = {}, submitFunction = (value = {}) => {}) {
		const box = document.createElement("div")
		box.classList.add("formModal")
		let idList = []
		let str = `
		<div id="formModal_modalMask"></div>
		<div id="formModal_content">
			<h4 id="formModal_H">${title}</h4>
			<div id="formModal_form">
		`
		for (const key in component) {
			if (key.includes("input")) {
				str += `<label>`
				let strTemp = `<input `
				component[key].type && (strTemp += `type=${component[key].type} `)
				component[key].prompt && (strTemp = `<span>${component[key].prompt}</span>` + strTemp)
				component[key].placeholder && (strTemp += `placeholder=${component[key].placeholder} `)
				component[key].name && (strTemp += `name=${component[key].name} `)
				component[key].id ? ((strTemp += `id=${component[key].id} `), idList.push(component[key].id)) : ((strTemp += `id=${key} `), idList.push(key))
				component[key].class && (strTemp += `class=${component[key].class} `)
				component[key].checked && (strTemp += `checked `)
				component[key].multiple && (strTemp += `multiple `)
				str += strTemp + `/></label>`
			} else if (key.includes("select")) {
				str += `<label> `
				let strTemp = `<select `
				component[key].prompt && (strTemp = `<span>${component[key].prompt}</span>` + strTemp)
				component[key].name && (strTemp += `name=${component[key].name} `)
				component[key].id ? ((strTemp += `id=${component[key].id} `), idList.push(component[key].id)) : ((strTemp += `id=${key} `), idList.push(key))
				component[key].class && (strTemp += `class=${component[key].class} `)
				strTemp += `>`
				for (const key2 in component[key]) {
					if (key2.includes("option")) {
						strTemp += `<option`
						component[key][key2].value && (strTemp += `value=${component[key][key2].value} `)
						component[key][key2].class && (strTemp += `class=${component[key][key2].class} `)
						strTemp += ">"
						component[key][key2].prompt && (strTemp += `${component[key][key2].prompt}`)
						strTemp += `</option> `
					}
				}
				str += strTemp + `</select></label>`
			} else if (key.includes("textarea")) {
				str += `<label> `
				let strTemp = `<textarea `
				component[key].prompt && (strTemp = `<span>${component[key].prompt}</span>` + strTemp)
				component[key].name && (strTemp += `name=${component[key].name} `)
				component[key].id ? ((strTemp += `id=${component[key].id} `), idList.push(component[key].id)) : ((strTemp += `id=${key} `), idList.push(key))
				component[key].class && (strTemp += `class=${component[key].class} `)
				component[key].cols && (strTemp += `cols=${component[key].cols} `)
				component[key].rows && (strTemp += `rows=${component[key].rows} `)
				component[key].resize && (strTemp += `style="resize:${component[key].resize};"`)
				str += strTemp + `></textarea></label>`
			}
		}
		str += `
			</div>
			<div id="formModal_Btns">
				<a id="formModal_cancel" href="javascript:;">取消</a>
				<a id="formModal_sure" href="javascript:;">提交</a>
			</div>
		</div>
		`
		box.innerHTML = str
		document.body.append(box)
		boxStyle()
		setTimeout(() => {
			box.style.opacity = 1
		}, 50)
		//确认按钮
		formModal_sure.addEventListener("click", () => {
			const data = getData()
			remove()
			submitFunction(data)
		})
		//取消按钮
		formModal_cancel.addEventListener("click", () => {
			remove()
		})
		//移除盒子
		function remove() {
			box.style.opacity = 0
			setTimeout(() => {
				box.remove()
			}, 300)
		}
		//获取表单数据
		function getData() {
			let data = {}
			idList.forEach(item => {
				data[item] = document.querySelector(`#${item}`).value
			})
			return data
		}

		//style样式
		function boxStyle() {
			box.style.display = "none"
			box.style.opacity = 0
			box.style.height = "100vh"
			box.style.width = "100vw"
			box.style.position = "absolute"
			box.style.top = "0"
			box.style.left = "0"
			box.style.transition = "all 0.2s"
			box.style.zIndex = "999"
			formModal_form.style.width = "100%"
			formModal_form.style.overflowX = "hidden"
			formModal_form.style.overflowY = "auto"
			const label = document.querySelectorAll("#formModal_form label")
			const span = document.querySelectorAll("#formModal_form label span")
			const input = document.querySelectorAll("#formModal_form label input")
			const select = document.querySelectorAll("#formModal_form label select")
			const textarea = document.querySelectorAll("#formModal_form label textarea")
			label.forEach(item => {
				item.style.display = "flex"
				item.style.width = "100%"
				item.style.margin = "10px"
				item.style.textAlign = "center"
			})
			span.forEach(item => {
				item.style.display = "block"
				item.style.height = "100%"
				item.style.width = "50px"
				item.style.marginRight = "5px"
				item.style.textAlign = "right"
				item.style.overflow = "hidden"
				item.style.fontSize = "12px"
				item.style.flex = "1"
			})
			input.forEach(item => {
				item.style.height = "25px"
				item.style.paddingLeft = "5px"
				item.style.backgroundColor = "#e4e4e4"
				item.style.border = "none"
				item.style.outline = "unset"
				item.style.width = "250px"
				item.style.marginRight = "50px"
				item.style.borderRadius = "5px"
			})
			select.forEach(item => {
				item.style.height = "25px"
				item.style.width = "255px"
				item.style.padding = "3px"
				item.style.backgroundColor = "#e4e4e4"
				item.style.marginRight = "50px"
				item.style.borderRadius = "5px"
				item.style.border = "none"
				item.style.outline = "unset"
			})
			textarea.forEach(item => {
				item.style.width = "250px"
				item.style.padding = "3px"
				item.style.backgroundColor = "#e4e4e4"
				item.style.marginRight = "50px"
				item.style.borderRadius = "5px"
				item.style.border = "none"
				item.style.outline = "unset"
			})
			formModal_modalMask.style.height = "100%"
			formModal_modalMask.style.width = "100%"
			formModal_modalMask.style.backgroundColor = "rgba(0, 0, 0, 0.5)"
			formModal_modalMask.style.transition = "all 0.3s"
			formModal_modalMask.style.zIndex = "998"
			formModal_content.style.width = "500px"
			formModal_content.style.position = "absolute"
			formModal_content.style.top = "10%"
			formModal_content.style.left = "50%"
			formModal_content.style.transform = "translateX(-50%)"
			formModal_content.style.borderRadius = "15px"
			formModal_content.style.transition = "all 0.3s"
			formModal_content.style.boxSizing = "border-box"
			formModal_content.style.backgroundColor = "#fff"
			formModal_content.style.display = "flex"
			formModal_content.style.flexDirection = "column"
			formModal_content.style.textAlign = "center"
			formModal_content.style.justifyContent = "space-between"
			formModal_content.style.border = "1px solid #fff"
			formModal_H.style.padding = "10px"
			formModal_H.style.height = "35px"
			formModal_H.style.lineHeight = "30px"
			formModal_H.style.fontSize = "20px"
			formModal_H.style.color = "#333"
			formModal_H.style.fontWeight = "normal"
			formModal_H.style.borderBottom = "1px solid"
			formModal_H.style.paddingLeft = "10px"
			formModal_Btns.style.display = "flex"
			formModal_Btns.style.justifyContent = "center"
			formModal_Btns.style.padding = "10px"
			formModal_sure.style.textAlign = "center"
			formModal_sure.style.textDecoration = "none"
			formModal_sure.style.color = "#fff"
			formModal_sure.style.display = "block"
			formModal_sure.style.height = "32px"
			formModal_sure.style.lineHeight = "32px"
			formModal_sure.style.borderRadius = "8px"
			formModal_sure.style.marginRight = "10px"
			formModal_sure.style.width = "120px"
			formModal_sure.style.backgroundColor = "rgb(39, 114, 255)"
			formModal_cancel.style.textAlign = "center"
			formModal_cancel.style.textDecoration = "none"
			formModal_cancel.style.color = "#fff"
			formModal_cancel.style.display = "block"
			formModal_cancel.style.height = "32px"
			formModal_cancel.style.lineHeight = "32px"
			formModal_cancel.style.borderRadius = "8px"
			formModal_cancel.style.marginRight = "10px"
			formModal_cancel.style.width = "80px"
			formModal_cancel.style.backgroundColor = "rgb(119, 119, 119)"
			box.style.display = "block"
		}
	},

	/**
	 * 根据传入元素，整理表单全部value、值或选择情况，并执行回调函数。
	 * 回调函数形参：value(表单全部值的对象)，item(表单父元素)
	 * @param {表单区域父元素} element Element
	 * @param {提交按钮执行函数} submitFunction Function
	 * @param {执行函数形参表单全部值的对象} submitFunction_value Object
	 * @param {执行函数形参表单父元素} submitFunction_item Element
	 *
	 */
	HTML: function (element, submitFunction = (value = {}) => {}) {
		const ele = existElement(element, "未找到元素(form.HTML):")
		if (ele[0]) {
			ele[1].addEventListener("submit", function (item) {
				item.preventDefault()
				let value = {}
				getTag("[type='text']", "text")
				getTag("[type='password']", "password")
				getTag("select", "select")
				getTag("textarea", "textarea")
				function getTag(tag, name) {
					if (!ele[1].querySelector(tag)) return
					ele[1].querySelectorAll(tag).forEach((item, index) => {
						!value[name] && (value[name] = {})
						value[name][item.id ? item.id : item.name ? item.name : name + index] = item.value
					})
				}
				getCheck("[type='radio']")
				getCheck("[type='checkbox']")
				function getCheck(tag) {
					if (!ele[1].querySelector(tag)) return
					let nameList = []
					let num = 0
					ele[1].querySelectorAll(tag).forEach(item => {
						!nameList.length && nameList.push(item.name)
						nameList[num] != item.name && ++num && nameList.push(item.name)
					})
					nameList.forEach(item => {
						ele[1].querySelectorAll(tag + `[name=${item}]`).forEach(item => {
							if (item.type == "checkbox") {
								!value["checkbox"] && (value["checkbox"] = {})
								!value["checkbox"][item.name] && (value["checkbox"][item.name] = { status: [], checkedValue: [] })
								value["checkbox"][item.name].status.push(item.checked)
								item.checked && value["checkbox"][item.name].checkedValue.push(item.value)
							}
							if (item.type == "radio") {
								!value["radio"] && (value["radio"] = {})
								!value["radio"][item.name] && (value["radio"][item.name] = { status: [], checkedValue: "" })
								value["radio"][item.name].status.push(item.checked)
								item.checked && (value["radio"][item.name].checkedValue = item.value)
							}
						})
					})
				}
				getFile("[type='file']", "file")
				function getFile(tag, name) {
					if (!ele[1].querySelector(tag)) return
					ele[1].querySelectorAll(tag).forEach((item, index) => {
						!value[name] && (value[name] = {})
						const key = item.id ? item.id : item.name ? item.name : name + index
						value[name][key] = []
						const files = item.files
						for (let i = 0; i < files.length; i++) {
							value[name][key][i] = files[i]
						}
					})
				}
				submitFunction(value, item)
			})
		}
	},
	/**
	 * 根据传入元素，整理表单全部value、值或选择情况，并返回表单数据
	 * @param {表单区域父元素} element Element
	 * @returns data
	 */
	getValue: function (element) {
		const ele = existElement(element, "未找到元素(form.getValue):")
		if (ele[0]) {
			let value = {}
			getTag("[type='text']", "text")
			getTag("[type='password']", "password")
			getTag("select", "select")
			getTag("textarea", "textarea")
			function getTag(tag, name) {
				if (!element.querySelector(tag)) return
				element.querySelectorAll(tag).forEach((item, index) => {
					!value[name] && (value[name] = {})
					value[name][item.id ? item.id : item.name ? item.name : name + index] = item.value
				})
			}
			getCheck("[type='radio']")
			getCheck("[type='checkbox']")
			function getCheck(tag) {
				if (!ele[1].querySelector(tag)) return
				let nameList = []
				let num = 0
				ele[1].querySelectorAll(tag).forEach(item => {
					!nameList.length && nameList.push(item.name)
					nameList[num] != item.name && ++num && nameList.push(item.name)
				})
				nameList.forEach(item => {
					ele[1].querySelectorAll(tag + `[name=${item}]`).forEach(item => {
						if (item.type == "checkbox") {
							!value["checkbox"] && (value["checkbox"] = {})
							!value["checkbox"][item.name] && (value["checkbox"][item.name] = { status: [], checkedValue: [] })
							value["checkbox"][item.name].status.push(item.checked)
							item.checked && value["checkbox"][item.name].checkedValue.push(item.value)
						}
						if (item.type == "radio") {
							!value["radio"] && (value["radio"] = {})
							!value["radio"][item.name] && (value["radio"][item.name] = { status: [], checkedValue: "" })
							value["radio"][item.name].status.push(item.checked)
							item.checked && (value["radio"][item.name].checkedValue = item.value)
						}
					})
				})
			}
			getFile("[type='file']", "file")
			function getFile(tag, name) {
				if (!ele[1].querySelector(tag)) return
				ele[1].querySelectorAll(tag).forEach((item, index) => {
					!value[name] && (value[name] = {})
					const key = item.id ? item.id : item.name ? item.name : name + index
					value[name][key] = []
					const files = item.files
					for (let i = 0; i < files.length; i++) {
						value[name][key][i] = files[i]
					}
				})
			}
			return value
		}
	},
	/**
	 * 根据传入元素，整理表单全部value、值或选择情况，会对空内容进行标红处理，并执行回调函数。
	 * 回调函数形参：value(表单全部值的对象)，isEmpty(是否有空内容元素)，isDetail(是否含有自定义错误)，item(表单父元素)
	 * @param {表单区域父元素} element Element
	 * @param {是否开启空内容检测} admitEmpty Boolean
	 * @param {表单元素错误详情控制} detail
	 * @param {提交按钮执行函数} submitFunction Function
	 * @param {执行函数形参表单全部值的对象} submitFunction_value Object
	 * @param {执行函数形参是否有空内容元素} submitFunction_isEmpty Boolean
	 * @param {执行函数形参是否含有自定义错误} submitFunction_isDetail Boolean
	 * @param {执行函数形参表单父元素} submitFunction_item Element
	 */
	/* detail格式：
	[
		{
			//class，name，id 三选一进行定位
			//仅仅只匹配第一个符合的元素
			class:"类名",
			name:"",
			id:"",

			//为空判断
			empty:true,
			//空值执行函数
			toEmpty:function (){},

			//长度限定
			length:[6,30],
			//长度不符执行函数
			toLength:function (){},

			//正则限定
			reg:"",
			//正则不符执行函数
			toReg:function (){},

			//以上判断有任意一个不成功的执行函数
			to:function (){}
		}
	]
	*/
	require: function (element, admitEmpty = true, detail = [], submitFunction = (value = {}, isEmpty, item) => {}) {
		const ele = existElement(element, "未找到元素(form.require):")
		if (ele[0]) {
			let styleBorder = {}
			let styleBackground = {}
			let styleOutline = {}
			let arrNum = 0
			ele[1].addEventListener("submit", function (item) {
				let isEmpty = false
				item.preventDefault()
				if (admitEmpty) {
					styleRe(styleBorder, "border")
					styleRe(styleBackground, "backgroundColor")
					styleRe(styleOutline, "outline")
				}
				function styleRe(obj, styleKey) {
					if (!isEmptyObj(obj)) {
						for (const key in obj) {
							obj[key].style[styleKey] = key.substring(0, key.indexOf("**"))
						}
					}
				}
				let value = {}
				getTag("[type='text']", "text")
				getTag("[type='password']", "password")
				getTag("select", "select")
				getTag("textarea", "textarea")
				function styleAdd(item) {
					styleBorder[item.style.border + "**" + arrNum++] = item
					styleBackground[item.style.backgroundColor + "**" + arrNum++] = item
					item.style.border = "2px solid rgb(255, 105, 105)"
					item.style.backgroundColor = "rgb(255, 228, 228)"
				}
				function getTag(tag, name) {
					if (!ele[1].querySelector(tag)) return
					ele[1].querySelectorAll(tag).forEach((item, index) => {
						!value[name] && (value[name] = {})
						if (admitEmpty) {
							if ((name == "text" || name == "textarea" || name == "password") && item.value == "") {
								isEmpty = true
								styleAdd(item)
							}
							if (name == "select" && item.value == item.children[0].value) {
								isEmpty = true
								styleAdd(item)
							}
						}
						value[name][item.id ? item.id : item.name ? item.name : name + index] = item.value
					})
				}
				getCheck("[type='radio']")
				getCheck("[type='checkbox']")
				function getCheck(tag) {
					if (!ele[1].querySelector(tag)) return
					let nameList = []
					let num = 0
					ele[1].querySelectorAll(tag).forEach(item => {
						!nameList.length && nameList.push(item.name)
						nameList[num] != item.name && ++num && nameList.push(item.name)
					})
					nameList.forEach(item => {
						ele[1].querySelectorAll(tag + `[name=${item}]`).forEach(item => {
							if (item.type == "checkbox") {
								!value["checkbox"] && (value["checkbox"] = {})
								!value["checkbox"][item.name] && (value["checkbox"][item.name] = { status: [], checkedValue: [] })
								value["checkbox"][item.name].status.push(item.checked)
								item.checked && value["checkbox"][item.name].checkedValue.push(item.value)
							}
							if (item.type == "radio") {
								!value["radio"] && (value["radio"] = {})
								!value["radio"][item.name] && (value["radio"][item.name] = { status: [], checkedValue: "" })
								value["radio"][item.name].status.push(item.checked)
								item.checked && (value["radio"][item.name].checkedValue = item.value)
							}
						})
					})
				}
				if (admitEmpty) {
					styleAdd2("checkbox")
					styleAdd2("radio")
				}
				function styleAdd2(tagName) {
					if (value[tagName]) {
						for (const key in value[tagName]) {
							if (!value[tagName][key].status.some(item => item == true)) {
								isEmpty = true
								document.querySelectorAll(`[type='${tagName}'][name='${key}']`).forEach(item => {
									styleOutline[item.style.outline + "**" + arrNum++] = item
									item.style.outline = "2px solid rgb(255, 105, 105)"
								})
							}
						}
					}
				}
				getFile("[type='file']", "file")
				function getFile(tag, name) {
					if (!ele[1].querySelector(tag)) return
					ele[1].querySelectorAll(tag).forEach((item, index) => {
						!value[name] && (value[name] = {})
						const key = item.id ? item.id : item.name ? item.name : name + index
						value[name][key] = []
						const files = item.files
						for (let i = 0; i < files.length; i++) {
							value[name][key][i] = files[i]
						}
					})
				}
				if (admitEmpty && value.file) {
					for (const key in value.file) {
						if (!value.file[key].length) {
							isEmpty = true
							document.querySelectorAll(`[type='file'][name='${key}']`).forEach(item => {
								styleAdd(item)
							})
						}
					}
				}
				let isDetail = false
				detail.forEach(item => {
					if (item.class || item.id || item.name) {
						let eleName = ""
						if (item.class) eleName = `.${item.class}`
						if (item.id) eleName = `#${item.id}`
						if (item.name) eleName = `[name=${item.name}]`
						const ele = document.querySelector(eleName)
						let value = ele.value
						if (ele.tagName == "TEXTAREA") value = ele.innerText
						if (item.empty && (value == "" || value == null || value == undefined)) {
							isDetail = true
							item.toEmpty && item.toEmpty()
							item.to && item.to()
							return
						}
						if (item.length && !(value.length >= item.length[0] && value.length <= item.length[1])) {
							isDetail = true
							item.toLength && item.toLength()
							item.to && item.to()
							return
						}
						if (item.reg) {
							let regStr = String(item.reg)
							if (regStr.substring(0, 1) == "/") regStr = regStr.substring(1, regStr.length - 1)
							if (!new RegExp(regStr).test(value)) {
								isDetail = true
								item.toReg && item.toReg()
								item.to && item.to()
								return
							}
						}
						isDetail = false
					}
				})
				submitFunction(value, isEmpty, isDetail, item)
			})
		}
	},
	/**
	 * 根据传入元素，整理表单全部value、值或选择情况，会对空内容进行标红处理，并返回表单数据
	 * @param {表单区域父元素} element Element
	 * @param {是否开启空内容检测} admitEmpty Boolean
	 * @param {表单元素错误详情控制} detail
	 * @returns 数据与判断结果 {data,isEmpty,isDetail}
	 */
	getValueRequire: function (element, admitEmpty = true, detail = []) {
		const ele = existElement(element, "未找到元素(form.getValueRequire):")
		if (ele[0]) {
			let isEmpty = false
			let arrNum = 0
			if (admitEmpty) {
				styleRe(styleBorder, "border")
				styleRe(styleBackground, "backgroundColor")
				styleRe(styleOutline, "outline")
			}
			function styleRe(obj, styleKey) {
				if (!isEmptyObj(obj)) {
					for (const key in obj) {
						obj[key].style[styleKey] = key.substring(0, key.indexOf("**"))
					}
				}
			}
			let value = {}
			getTag("[type='text']", "text")
			getTag("[type='password']", "password")
			getTag("select", "select")
			getTag("textarea", "textarea")
			function styleAdd(item) {
				styleBorder[item.style.border + "**" + arrNum++] = item
				styleBackground[item.style.backgroundColor + "**" + arrNum++] = item
				item.style.border = "2px solid rgb(255, 105, 105)"
				item.style.backgroundColor = "rgb(255, 228, 228)"
			}
			function getTag(tag, name) {
				if (!ele[1].querySelector(tag)) return
				ele[1].querySelectorAll(tag).forEach((item, index) => {
					!value[name] && (value[name] = {})
					if (admitEmpty) {
						if ((name == "text" || name == "textarea" || name == "password") && item.value == "") {
							isEmpty = true
							styleAdd(item)
						}
						if (name == "select" && item.value == item.children[0].value) {
							isEmpty = true
							styleAdd(item)
						}
					}
					value[name][item.id ? item.id : item.name ? item.name : name + index] = item.value
				})
			}
			getCheck("[type='radio']")
			getCheck("[type='checkbox']")
			function getCheck(tag) {
				if (!ele[1].querySelector(tag)) return
				let nameList = []
				let num = 0
				ele[1].querySelectorAll(tag).forEach(item => {
					!nameList.length && nameList.push(item.name)
					nameList[num] != item.name && ++num && nameList.push(item.name)
				})
				nameList.forEach(item => {
					ele[1].querySelectorAll(tag + `[name=${item}]`).forEach(item => {
						if (item.type == "checkbox") {
							!value["checkbox"] && (value["checkbox"] = {})
							!value["checkbox"][item.name] && (value["checkbox"][item.name] = { status: [], checkedValue: [] })
							value["checkbox"][item.name].status.push(item.checked)
							item.checked && value["checkbox"][item.name].checkedValue.push(item.value)
						}
						if (item.type == "radio") {
							!value["radio"] && (value["radio"] = {})
							!value["radio"][item.name] && (value["radio"][item.name] = { status: [], checkedValue: "" })
							value["radio"][item.name].status.push(item.checked)
							item.checked && (value["radio"][item.name].checkedValue = item.value)
						}
					})
				})
			}
			if (admitEmpty) {
				styleAdd2("checkbox")
				styleAdd2("radio")
			}
			function styleAdd2(tagName) {
				if (value[tagName]) {
					for (const key in value[tagName]) {
						if (!value[tagName][key].status.some(item => item == true)) {
							isEmpty = true
							document.querySelectorAll(`[type='${tagName}'][name='${key}']`).forEach(item => {
								styleOutline[item.style.outline + "**" + arrNum++] = item
								item.style.outline = "2px solid rgb(255, 105, 105)"
							})
						}
					}
				}
			}
			getFile("[type='file']", "file")
			function getFile(tag, name) {
				if (!ele[1].querySelector(tag)) return
				ele[1].querySelectorAll(tag).forEach((item, index) => {
					!value[name] && (value[name] = {})
					const key = item.id ? item.id : item.name ? item.name : name + index
					value[name][key] = []
					const files = item.files
					for (let i = 0; i < files.length; i++) {
						value[name][key][i] = files[i]
					}
				})
			}
			if (admitEmpty && value.file) {
				for (const key in value.file) {
					if (!value.file[key].length) {
						isEmpty = true
						document.querySelectorAll(`[type='file'][name='${key}']`).forEach(item => {
							styleAdd(item)
						})
					}
				}
			}
			let isDetail = false
			detail.forEach(item => {
				if (item.class || item.id || item.name) {
					let eleName = ""
					if (item.class) eleName = `.${item.class}`
					if (item.id) eleName = `#${item.id}`
					if (item.name) eleName = `[name=${item.name}]`
					const ele = document.querySelector(eleName)
					let value = ele.value
					if (ele.tagName == "TEXTAREA") value = ele.innerText
					if (item.empty && (value == "" || value == null || value == undefined)) {
						isDetail = true
						item.toEmpty && item.toEmpty()
						item.to && item.to()
						return
					}
					if (item.length && !(value.length >= item.length[0] && value.length <= item.length[1])) {
						isDetail = true
						item.toLength && item.toLength()
						item.to && item.to()
						return
					}
					if (item.reg) {
						let regStr = String(item.reg)
						if (regStr.substring(0, 1) == "/") regStr = regStr.substring(1, regStr.length - 1)
						if (!new RegExp(regStr).test(value)) {
							isDetail = true
							item.toReg && item.toReg()
							item.to && item.to()
							return
						}
					}
					isDetail = false
				}
			})
			return { value, isEmpty, isDetail }
		}
	},

	/**
	 * 睁眼SVG图像
	 * 用于密码框显示
	 * 已有方法对其进行调用
	 */
	openEyeSVG: `<svg t="1695451059690" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1723" width="200" height="200"><path d="M512 832c-156.448 0-296.021333-98.730667-418.410667-291.605333a52.938667 52.938667 0 0 1 0-56.789334C215.978667 290.730667 355.552 192 512 192c156.448 0 296.021333 98.730667 418.410667 291.605333a52.938667 52.938667 0 0 1 0 56.789334C808.021333 733.269333 668.448 832 512 832z m0-576c-129.514667 0-249.461333 83.850667-360.117333 256C262.538667 684.149333 382.485333 768 512 768c129.514667 0 249.461333-83.850667 360.117333-256C761.461333 339.850667 641.514667 256 512 256z m0 405.333333c-83.210667 0-150.666667-66.858667-150.666667-149.333333S428.789333 362.666667 512 362.666667s150.666667 66.858667 150.666667 149.333333S595.210667 661.333333 512 661.333333z m0-64c47.552 0 86.101333-38.208 86.101333-85.333333S559.552 426.666667 512 426.666667c-47.552 0-86.101333 38.208-86.101333 85.333333s38.549333 85.333333 86.101333 85.333333z" fill="#000000" p-id="1724"></path></svg>`,
	/**
	 * 闭眼SVG图像
	 * 用于密码框显示
	 * 已有方法对其进行调用
	 */
	closeEyeSVG: `<svg t="1695451008027" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1585" width="200" height="200"><path d="M930.024 339.358c8.607-12.84 5.644-29.914-5.644-39.933-12.84-10.018-29.915-7.196-39.933 5.644-1.411 1.411-159.731 188.235-347.965 188.235-182.59 0-347.966-188.235-349.377-189.646-10.018-11.43-28.503-12.84-39.932-2.822-11.43 10.019-12.84 28.503-2.822 39.933 2.822 4.233 37.11 42.755 91.295 85.51l-72.81 75.632c-11.43 11.43-10.02 29.914 1.41 39.933 2.822 5.644 10.019 8.607 17.074 8.607 7.196 0 14.252-2.822 20.037-8.607l78.454-81.277c37.111 25.681 81.277 49.951 129.817 67.025l-29.914 101.314c-4.233 15.662 4.233 31.325 20.037 35.7h8.607c12.84 0 24.27-8.608 27.092-21.449l29.915-101.313c22.859 4.233 47.129 7.196 71.258 7.196 24.27 0 48.54-2.822 71.258-7.196l29.914 99.902c2.822 12.84 15.663 21.448 27.092 21.448 2.823 0 5.645 0 7.197-1.41 15.662-4.234 24.27-20.038 20.037-35.7l-30.338-99.903c48.54-17.074 92.706-41.344 129.817-67.025l77.043 79.866c5.644 5.644 12.84 8.607 20.037 8.607s14.252-2.822 20.037-8.607c11.43-11.43 11.43-28.504 1.411-39.933l-72.669-75.632c58.276-42.755 92.565-84.1 92.565-84.1z m0 0" p-id="1586"></path></svg>`,

	/**
	 * 为密码框架加上眼睛效果，并控制密码框类型变换。
	 * 具有默认图标效果。
	 * 也可以通过传参(iconFontClose、iconFontOpen)来自定义调整图案。
	 * 如果自定义调整，需要将两个形参都传递
	 * @param {密码框元素} element Element
	 * @param {闭眼字体图标_可选} iconFontClose String
	 * @param {睁眼字体图标_可选} iconFontOpen String
	 * @returns span Element
	 */
	eye: function (element = "", iconFontClose = "", iconFontOpen = "") {
		const ele = existElement(element, "未找到元素(form.eye):")
		if (ele[0]) {
			if (ele[1].type != "password") return console.error("非密码框(form.eye)：" + ele[1])
			const span = document.createElement("span")
			if (iconFontClose && iconFontOpen) {
				span.classList.add(`iconfont`)
				span.classList.add(`${iconFontClose}`)
			} else {
				span.innerHTML = this.closeEyeSVG
			}
			const spanHeight = 21
			const spanWidth = 21
			span.style.position = "absolute"
			span.style.display = "flex"
			span.style.justifyContent = "center"
			span.style.alignItems = "center"
			span.style.cursor = "pointer"
			span.style.overflow = "hidden"
			style()
			ele[1].after(span)
			span.addEventListener("mousedown", () => {
				if (iconFontClose && iconFontOpen) {
					span.classList.remove(`iconfont`)
					span.classList.remove(`${iconFontClose}`)
					span.classList.add(`iconfont`)
					span.classList.add(`${iconFontOpen}`)
				} else {
					span.innerHTML = this.openEyeSVG
				}
				ele[1].type = "text"
			})
			span.addEventListener("mouseup", () => {
				if (iconFontClose && iconFontOpen) {
					span.classList.remove(`iconfont`)
					span.classList.remove(`${iconFontOpen}`)
					span.classList.add(`iconfont`)
					span.classList.add(`${iconFontClose}`)
				} else {
					span.innerHTML = this.closeEyeSVG
				}
				ele[1].type = "password"
			})
			span.addEventListener("mouseout", () => {
				if (iconFontClose && iconFontOpen) {
					span.classList.remove(`iconfont`)
					span.classList.remove(`${iconFontOpen}`)
					span.classList.add(`iconfont`)
					span.classList.add(`${iconFontClose}`)
				} else {
					span.innerHTML = this.closeEyeSVG
				}
				ele[1].type = "password"
			})
			window.addEventListener("resize", () => style())
			function style() {
				span.style.height = spanHeight + "px"
				span.style.width = spanWidth + "px"
				span.style.top = ele[1].offsetTop + (ele[1].offsetHeight - spanHeight) / 2 + "px"
				span.style.left = ele[1].offsetLeft + ele[1].offsetWidth - spanWidth + "px"
			}
			return span
		}
	},
	/**
	 * 为多行文本加上字数显示与限制字数
	 * @param {多行文本元素} element Element
	 * @param {限定字数} length Number
	 * @returns span Element
	 */
	textareaLength: function (element = "", length = 20) {
		const ele = existElement(element, "未找到元素(form.textareaLength):")
		if (ele[0]) {
			if (ele[1].tagName != "TEXTAREA") return console.error("非多行文本输入框(form.textareaLength)：" + ele[1])
			const span = document.createElement("span")
			span.innerText = `0/${length}`
			span.style.display = "block"
			span.style.position = "absolute"
			span.style.color = "rgb(166, 166, 166)"
			span.style.opacity = 0
			span.style.transition = "all 0.2s"
			style()
			ele[1].after(span)
			window.addEventListener("resize", () => style())
			ele[1].addEventListener("mousemove", () => style())
			ele[1].addEventListener("focus", () => (span.style.opacity = 1))
			ele[1].addEventListener("blur", () => (span.style.opacity = 0))
			let isComposition = false
			ele[1].addEventListener("compositionstart", () => (isComposition = true))
			ele[1].addEventListener("compositionend", () => ((isComposition = false), to()))
			ele[1].addEventListener("input", () => {
				if (!isComposition) to()
			})
			function to() {
				if (ele[1].value.length >= length) {
					ele[1].value = ele[1].value.substring(0, length)
					span.style.color = "rgb(2, 159, 2)"
				} else {
					span.style.color = "rgb(166, 166, 166)"
				}
				span.innerText = `${ele[1].value.length}/${length}`
			}
			function style() {
				span.style.transition = "none"
				span.style.fontSize = ele[1].style.fontSize + "px"
				span.style.top = ele[1].offsetTop + ele[1].offsetHeight + "px"
				span.style.left = ele[1].offsetLeft + ele[1].offsetWidth + "px"
				span.style.transform = "translate(-130%,-130%)"
				span.style.transition = "all 0.2s"
			}
			return span
		}
	}
}

/**
 * css样式类
 */
const css = {
	/**
	 * 单个元素的样式设置
	 * @param {CSS选择器或元素} element
	 * @param {样式对象} styleList
	 * @returns 元素
	 */
	style: function (element, styleList = {}) {
		if (!(styleList instanceof Object)) {
			console.log("非对象!(第二个形参)：" + styleList)
			return
		}
		const ele = existElement(element, "未找到元素(css.style):")
		if (ele[0]) {
			for (const key in styleList) {
				ele[1].style[formKey(key)] = styleList[key]
			}
			function formKey(key = "") {
				if (!key.includes("-")) return key
				const index = key.indexOf("-")
				key.substring(0, index) + key.substring(index + 1, index + 2).toUpperCase() + key.substring(index + 2, key.length)
			}
			return ele[1]
		}
	},
	/**
	 * 多个同名元素的样式设置
	 * @param {CSS选择器或元素伪数组} elements
	 * @param {样式对象} styleList
	 * @returns 元素伪数组
	 */
	styles: function (elements, styleList = {}) {
		if (!(styleList instanceof Object)) {
			console.log("非对象!(第二个形参)：" + styleList)
			return
		}
		const ele = existElements(elements, "未找到元素(css.styles):")
		if (ele[0]) {
			try {
				ele[1].forEach(item => {
					for (const key in styleList) {
						item.style[formKey(key)] = styleList[key]
					}
				})
			} catch {
				for (const key in styleList) {
					ele[1].style[formKey(key)] = styleList[key]
				}
			}
			function formKey(key = "") {
				if (!key.includes("-")) return key
				const index = key.indexOf("-")
				key.substring(0, index) + key.substring(index + 1, index + 2).toUpperCase() + key.substring(index + 2, key.length)
			}
			return ele[1]
		}
	},
	/**
	 * 滚动条自定义样式设置
	 * @param {滚动条背景样式} style Object
	 * @param {滚动条轨道样式} style.track Object
	 * @param {滚动条滑块样式} style.thumb Object
	 */
	scrollbar: function (style = { track: {}, thumb: {} }) {
		let css = `<style css-id="scroll">`
		if (style.track) {
			css += `::-webkit-scrollbar-track {`
			for (const key in style.track) {
				css += `${formStyle(key)}:${style.track[key]};`
			}
			css += `}`
		}
		if (style.thumb) {
			css += `::-webkit-scrollbar-thumb {`
			for (const key in style.thumb) {
				css += `${formStyle(key)}:${style.thumb[key]};`
			}
			css += `}`
		}
		let css2 = ``
		for (const key in style) {
			if (key != "track" && key != "thumb") {
				!css2 && (css2 = `::-webkit-scrollbar {`)
				css2 += `${formStyle(key)}:${style[key]};`
			}
		}
		css2 && (css += css2 + `}`)
		css += `</style>`
		const scrollID = document.querySelector('[css-id="scroll]')
		const head = document.querySelector("head")
		scrollID && head.removeChild(scrollID)
		head.innerHTML += css
		function formStyle(styleKey) {
			if (!/[A-Z]+/.test(styleKey)) return styleKey
			return styleKey
				.split("")
				.map(item => {
					if (/[A-Z]+/.test(item)) return "-" + item.toLowerCase()
					return item
				})
				.join("")
		}
	}
}

/**
 * 单元素单事件绑定的简写形式
 * 类似检测按键的，可以在listeners中传入对象{事件类型：按键/鼠标按键}。
 * 对象封装的键盘检测有：keyCode、code、key；
 * 对象封装的鼠标检测有：button、buttons。
 * 如果有其他获取，e传入执行函数的第二个参数中
 * @param {绑定元素} element Element
 * @param {事件类型} listener String
 * @param {执行函数} executeFunction Function
 * @param {执行函数形参_事件对象} executeFunction_element Element
 * @param {执行函数形参_事件源} executeFunction_e
 */
function Listener(element, listener = "", executeFunction = function (e) {}) {
	const ele = existElement(element, "未找到元素(Listener):")
	if (!ele[0]) return
	if (typeof listener == "string") {
		ele[1].addEventListener(listener, function (e) {
			executeFunction.call(ele[1], ele[1], e)
		})
	} else {
		for (const key in listener) {
			ele[1].addEventListener(key, function (e) {
				if (e.keyCode == listener[key]) executeFunction.call(ele[1], ele[1], e)
				else if (e.code == listener[key]) executeFunction.call(ele[1], ele[1], e)
				else if (e.key == listener[key]) executeFunction.call(ele[1], ele[1], e)
				else if (e.button == listener[key]) executeFunction.call(ele[1], ele[1], e)
				else if (e.buttons == listener[key]) executeFunction.call(ele[1], ele[1], e)
			})
		}
	}
}
/**
 * 【单元素多事件绑定，执行同样的代码时使用】
 * 类似检测按键的，可以在listeners中传入对象{事件类型：按键/鼠标按键}。
 * 封装的键盘检测有：keyCode、code、key；
 * 封装的鼠标检测有：button、buttons。
 * 如果有其他获取，已将e传入执行函数的第二个参数中
 * @param {绑定元素} element Element
 * @param {事件类型数组} listeners StringArray
 * @param {执行函数} executeFunction Function
 * @param {执行函数形参_事件对象} executeFunction_element Element
 * @param {执行函数形参_事件源} executeFunction_e
 */
function Listeners(element, listeners = [], executeFunction = function (e) {}) {
	const ele = existElement(element, "未找到元素(Listeners):")
	if (!ele[0]) return
	listeners.forEach(item => {
		if (typeof item == "string") {
			ele[1].addEventListener(item, function (e) {
				executeFunction.call(ele[1], ele[1], e)
			})
		} else {
			for (const key in item) {
				ele[1].addEventListener(key, function (e) {
					if (e.keyCode == item[key]) executeFunction.call(ele[1], ele[1], e)
					else if (e.code == item[key]) executeFunction.call(ele[1], ele[1], e)
					else if (e.key == item[key]) executeFunction.call(ele[1], ele[1], e)
					else if (e.button == item[key]) executeFunction.call(ele[1], ele[1], e)
					else if (e.buttons == item[key]) executeFunction.call(ele[1], ele[1], e)
				})
			}
		}
	})
}

/**
 * 全部同名元素单事件绑定，执行同样的代码时使用
 * 类似检测按键的，可以在listener中传入对象{事件类型：按键/鼠标按键}。
 * 如果传入多个事件类型，只取第一个
 * 封装的键盘检测有：keyCode、code、key；
 * 封装的鼠标检测有：button、buttons。
 * 如果有其他获取，已将e传入执行函数的第二个参数中
 * @param {绑定同名元素} elements Element
 * @param {事件类型} listener String
 * @param {执行函数} executeFunction Function
 * @param {执行函数形参_事件对象} executeFunction_element Element
 * @param {执行函数形参_事件源} executeFunction_e
 */
function AllListener(elements, listener = "", executeFunction = function (e) {}) {
	const ele = existElements(elements, "未找到元素(AllListener):")
	if (!ele[0]) return
	ele[1].forEach(item => {
		if (typeof listener == "string") {
			item.addEventListener(listener, function (e) {
				executeFunction.call(item, item, e)
			})
		} else if (listener instanceof Object) {
			for (const key in listener) {
				item.addEventListener(key, function (e) {
					if (e.keyCode == listener[key]) executeFunction.call(item, item, e)
					else if (e.code == listener[key]) executeFunction.call(item, item, e)
					else if (e.key == listener[key]) executeFunction.call(item, item, e)
					else if (e.button == listener[key]) executeFunction.call(item, item, e)
					else if (e.buttons == listener[key]) executeFunction.call(item, item, e)
				})
			}
		}
	})
}

/**
 * 【多元素单事件绑定，执行同样的代码时使用】
 * 类似检测按键的，可以在listener中传入对象{事件类型：按键/鼠标按键}。
 * 如果传入多个事件类型，只取第一个
 * 封装的键盘检测有：keyCode、code、key；
 * 封装的鼠标检测有：button、buttons。
 * 如果有其他获取，已将e传入执行函数的第二个参数中
 * @param {绑定元素数组} elements ElementArray
 * @param {事件类型} listener String
 * @param {执行函数} executeFunction Function
 * @param {执行函数形参_事件对象} executeFunction_element Element
 * @param {执行函数形参_事件源} executeFunction_e
 */
function eventsListener(elements = [], listener = "", executeFunction = function (e) {}) {
	elements.forEach(item => {
		const ele = existElement(item, "未找到元素(eventsListener):")
		if (ele[0]) {
			if (typeof listener == "string") {
				item.addEventListener(listener, function (e) {
					executeFunction.call(item, item, e)
				})
			} else if (listener instanceof Object) {
				for (const key in listener) {
					item.addEventListener(key, function (e) {
						if (e.keyCode == listener[key]) executeFunction.call(item, item, e)
						else if (e.code == listener[key]) executeFunction.call(item, item, e)
						else if (e.key == listener[key]) executeFunction.call(item, item, e)
						else if (e.button == listener[key]) executeFunction.call(item, item, e)
						else if (e.buttons == listener[key]) executeFunction.call(item, item, e)
					})
				}
			}
		}
	})
}

/**
 * 元素内容渲染
 * @param {需要渲染内容的元素} element Element
 * @param {内容} content String
 * @param {是否覆盖渲染} cover Boolean
 * @returns 元素innerHTML内容
 */
function renderContent(element = "", content = "", cover = false) {
	const ele = existElement(element, "未找到元素(renderContent):")
	if (ele[0]) {
		if (cover) {
			element.innerHTML = content
		} else {
			element.innerHTML += content
		}
		return element.innerHTML
	}
}

/**
 * document.querySelector方法简写
 * @param {选择器或元素} element String
 * @returns element
 */
function dq(element = "") {
	const ele = existElement(element, "未找到元素(document.querySelector):")
	if (ele[0]) return ele[1]
}
/**
 * document.querySelectorAll方法简写
 * @param {选择器或元素} elements String
 * @returns elements
 */
function dqa(elements = "") {
	const ele = existElement(elements, "未找到元素(document.querySelectorAll):")
	if (ele[0]) return ele[1]
}

/**
 * 判断是否为空对象
 * @param {需要判断的对象} obj Object
 * @returns Boolean
 */
function isEmptyObj(obj = {}) {
	if (!(obj instanceof Object)) return undefined
	return JSON.stringify(obj) == "{}"
}
/**
 * 判断是否为空数组
 * @param {需要判断的数组} arr Array
 * @returns Boolean
 */
function isEmptyArr(arr = []) {
	if (!(arr instanceof Array)) return undefined
	return arr.length == 0
}

/**
 * 本地持久化存储方法
 * 自动进行JSON转换
 */
const local = {
	/**
	 * 本地持久化数据储存
	 * @param {属性名} dataName String
	 * @param {属性值} data
	 * @returns JSON||null
	 */
	set: function (dataName = "", data) {
		const type = Object.prototype.toString.call(dataName)
		if (!(type == "[object String]")) {
			console.error("储存失败(setItem)：属性名格式不正确[需求：string]")
			return null
		}
		if (data == "" || data == null || data == undefined) {
			console.error("储存失败(setItem)：请传入数据！")
			return null
		}
		localStorage.setItem(dataName, JSON.stringify(data))
		return JSON.stringify(data)
	},
	/**
	 * 获取本地存储数据，可传入执行函数直接处理，形参为数据
	 * @param {属性名} dataName String
	 * @param {获取成功后的执行函数} processingData Function
	 * @param {执行函数形参_已格式化的数据} processingData_data Data
	 * @returns data||null
	 */
	get: function (dataName = "", processingData = function (data) {}) {
		if (localStorage.getItem(dataName)) {
			const data = JSON.parse(localStorage.getItem(dataName))
			processingData(data)
			return data
		} else {
			console.error("获取失败(getItem)：未找到属性名为 " + dataName + " 的本地存储数据！")
			return null
		}
	},
	/**
	 * 删除本地数据
	 * @param {属性名} dataName String
	 * @param {是否显示未找到数据的错误提示} errInfo Boolean
	 * @returns Boolean
	 */
	remove: function (dataName = "", errInfo = true) {
		if (localStorage.getItem(dataName)) {
			localStorage.removeItem(dataName)
			return true
		} else {
			errInfo && console.error("删除失败(removeItem)：未找到属性名为 " + dataName + " 的本地存储数据！")
			return false
		}
	},
	/**
	 * 清空本地存储数据
	 */
	clear: function () {
		localStorage.clear()
	}
}
/**
 * 本地临时存储方法
 * 自动进行JSON转换
 */
const session = {
	/**
	 * 本地临时数据储存
	 * @param {属性名} dataName String
	 * @param {属性值} data
	 * @returns JSON||null
	 */
	set: function (dataName = "", data) {
		const type = Object.prototype.toString.call(dataName)
		if (!(type == "[object String]")) {
			console.error("储存失败(setItem)：属性名格式不正确[需求：string]")
			return null
		}
		if (data == "" || data == null || data == undefined) {
			console.error("储存失败(setItem)：请传入数据！")
			return null
		}
		sessionStorage.setItem(dataName, JSON.stringify(data))
		return JSON.stringify(data)
	},
	/**
	 * 获取本地存储数据，可传入执行函数直接处理，形参为数据
	 * @param {属性名} dataName String
	 * @param {获取成功后的执行函数} processingData Function
	 * @param {执行函数形参_已格式化的数据} processingData_data Data
	 * @returns data||null
	 */
	get: function (dataName = "", processingData = function (data) {}) {
		if (sessionStorage.getItem(dataName)) {
			const data = JSON.parse(sessionStorage.getItem(dataName))
			processingData(data)
			return data
		} else {
			console.error("获取失败(getItem)：未找到属性名为 " + dataName + " 的本地存储数据！")
			return null
		}
	},
	/**
	 * 删除本地数据
	 * @param {属性名} dataName String
	 * @param {是否显示未找到数据的错误提示} errInfo Boolean
	 * @returns Boolean
	 */
	remove: function (dataName = "", errInfo = true) {
		if (sessionStorage.getItem(dataName)) {
			sessionStorage.removeItem(dataName)
			return true
		} else {
			errInfo && console.error("删除失败(removeItem)：未找到属性名为 " + dataName + " 的本地存储数据！")
			return false
		}
	},
	/**
	 * 清空本地存储数据
	 */
	clear: function () {
		sessionStorage.clear()
	}
}

/**
 * 映射表构造函数
 * @param {映射表对象} Table Object
 */
function mapTable(Table) {
	this.Table = Table
}
/**
 * 查询映射表中是否存在某个key/value
 * @param {任意值} anyKey
 * @returns Boolean
 */
mapTable.prototype.seek = function (anyKey) {
	for (const key in this.Table) {
		if (key == anyKey) return true
		if (this.Table[key] == anyKey) return true
	}
	return false
}
/**
 * 查询映射表中是否存在某个value
 * @param {任意值} anyValue
 * @returns Boolean
 */
mapTable.prototype.seekValue = function (anyValue) {
	for (const key in this.Table) {
		if (this.Table[key] == anyValue) return true
	}
	return false
}
/**
 * 查询映射表中是否存在某个key
 * @param {任意值} anyKey
 * @returns Boolean
 */
mapTable.prototype.seekKey = function (anyKey) {
	for (const key in this.Table) {
		if (key == anyKey) return true
	}
	return false
}
/**
 * 返回映射表的对应key/value
 * @param {任意值} anyKey
 * @returns key/value
 */
mapTable.prototype.mapping = function (anyKey) {
	for (const key in this.Table) {
		if (key == anyKey) return this.Table[key]
		if (this.Table[key] == anyKey) return key
	}
}
/**
 * 往映射表中添加键值对
 * @param {对应对象} mapObj
 */
mapTable.prototype.add = function (mapObj) {
	for (const key in mapObj) {
		this.Table[key] = mapObj[key]
	}
}
/**
 * 删除映射表中的键值对，可传入key或value
 * @param {任意值} anyKey
 */
mapTable.prototype.del = function (anyKey) {
	for (const key in this.Table) {
		if (key == anyKey) {
			delete this.Table[anyKey]
			return
		}
		if (this.Table[key] == anyKey) {
			delete this.Table[key]
			return
		}
	}
}

/**
 * 获取指定长度的随机字符串
 * @param {长度} length Number
 * @param {是否开启特殊字符} special Boolean
 * @param {自定义特殊字符_可选} specialChar Array
 * @returns String
 */
function randomToken(length = 8, special = false, specialChar = []) {
	let token = ""
	for (let i = 0; i < length; i++) {
		const typeNum = Digit.randomInt(0, special ? 3 : 2, true)
		typeNum == 0 && (token += Digit.randomInt(0, 9, true))
		typeNum == 1 && (token += randomChar(charArr.Lowercase))
		typeNum == 2 && (token += randomChar(charArr.Uppercase))
		typeNum == 3 && (token += randomChar(specialChar.length ? specialChar : charArr.SpecialChar))
	}
	function randomChar(char = []) {
		return char[Digit.randomInt(0, char.length, false)]
	}
	return token
}

/**
 * 用来储存常用字符
 */
const charArr = {
	/**
	 * 小写字母
	 */
	Lowercase: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"],
	/**
	 * 大写字母
	 */
	Uppercase: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"],
	/**
	 * 数字
	 */
	Number: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
	/**
	 * 字符数字
	 */
	NumberChar: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
	/**
	 * 特殊字符
	 */
	SpecialChar: ["!", "@", "%", "&", "$", "_", "#", "^", "?", "+", "-", "*", "/", "=", "."]
}

/**
 * 元素是否存在
 * @param {元素或元素的css选择器} element String
 * @param {错误信息} errMsg
 * @returns Boolean
 */
function existElement(element, errMsg = "未找到元素:") {
	const elementStr = element
	if (elementStr == "" || elementStr == null || elementStr == undefined) {
		errMsg = errMsg + `\nDOM异常，未检测到页面元素！\n您的参数传递为空值！\n\n解决：\n请检查元素选择器是否书写正确\n或检查传入的元素是否存在！`
	} else {
		errMsg =
			errMsg +
			`\nDOM异常，未检测到页面元素！\n您的参数传递为（${elementStr}）\n${
				typeof elementStr == "string" ? "\n您的选择器分析如下：\n" + selectorAnalysis(elementStr) + "\n" : ""
			}\n解决：\n请检查元素选择器是否书写正确\n或检查传入的元素是否存在！`
	}

	try {
		element = typeof element == "string" ? (element == "window" ? window : document.querySelector(element)) : element
		if (element) return [true, element]
		else {
			console.error(errMsg)
			return [false, null]
		}
	} catch (e) {
		console.error(errMsg)
		return [false, null]
	}
}
/**
 * 元素是否存在
 * @param {元素伪数组或元素的css选择器} elements String
 * @param {错误信息} errMsg
 * @returns Boolean
 */
function existElements(elements, errMsg = "未找到元素:") {
	const elementsStr = elements
	if (elementsStr == "" || elementsStr == null || elementsStr == undefined) {
		errMsg = errMsg + `\nDOM异常，未检测到页面元素！\n您的参数传递为空值！\n\n解决：\n请检查元素选择器是否书写正确\n或检查传入的元素是否存在！`
	} else {
		errMsg =
			errMsg +
			`\nDOM异常，未检测到页面元素！\n您的参数传递为（${elementsStr}）\n${
				typeof elementsStr == "string" ? "\n您的选择器分析如下：\n" + selectorAnalysis(elementsStr) + "\n" : ""
			}\n解决：\n请检查元素选择器是否书写正确\n或检查传入的元素是否存在！`
	}
	try {
		elements = typeof elements == "string" ? (elements == "window" ? window : document.querySelectorAll(elements)) : elements
		if (elements == "window" || elements.length != 0) return [true, elements]
		else {
			console.error(errMsg)
			return [false, null]
		}
	} catch (e) {
		console.error(errMsg)
		return [false, null]
	}
}

/**
 * 解构分析选择器
 * @param {选择器} selector String
 * @returns String
 */
function selectorAnalysis(selector = "") {
	let str = ""
	selector = Str.removeSpace(selector)
	if (selector.indexOf(" ") != -1) {
		str += "元素结构为：\n"
		Str.subChar(selector, " ").forEach((item, index) => {
			str += index + 1 + ". "
			for (let i = 0; i < index; i++) {
				str += "    "
			}
			str += `${selectorAnalysis(item)}\n`
		})
	} else {
		selector.split("").forEach(item => {
			if (item == ".") str += ",且class属性为"
			else if (item == "#") str += ",且id属性为"
			else if (item == "[") str += ",且name属性为"
			else if (item == "=" || item == "]") {
			} else str += item
		})
		if (str.substring(0, 2) == ",且") {
			str = str.substring(2, str.length)
		} else {
			str = "标签为" + str
		}
		str += "的元素"
	}
	return str
}
